#문제

오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트 팀과 링크 팀으로 사람들을 나눠야 한다.

BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Sji이다.

N=4이고, S가 아래와 같은 경우를 살펴보자.

  1 2 3
4   5 6
7 1   2
3 4 5  

예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S12 + S21 = 1 + 4 = 5
  • 링크 팀: S34 + S43 = 2 + 5 = 7

1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S13 + S31 = 2 + 7 = 9
  • 링크 팀: S24 + S42 = 6 + 4 = 10

축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.

첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.

#작성 코드

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;

int N;
int S[20][20];
bool visit[20]={false,};
int minS=987654321;

void makeTeam(int n, int cnt){
	if( cnt == N/2 ){
		vector<int> start, link;
		 
		for(int i=0; i<N; i++){
			if( visit[i]==true )
				start.push_back(i);		// visit한 선수들은 start팀 
			else
				link.push_back(i);		// 다른 선수들은link팀. 
		}
		
		// 두 팀의 능력치 차이 구하기. 
		int teamStart=0, teamLink=0;
		for(int i=0; i<start.size(); i++){
			for(int j=i+1; j<start.size(); j++){
				int startX = start[i], startY = start[j];
				int linkX = link[i], linkY = link[j];
				teamStart+=S[startX][startY]+S[startY][startX];
				teamLink+=S[linkX][linkY]+S[linkY][linkX];
			}
		}
		minS = min(minS, abs(teamStart-teamLink));
		return;
	}
	
	// n번째 선수부터 탐색한다. 
	for(int i=n; i<N; i++){
		if(visit[i]==true) continue;
		visit[i] = true;
		makeTeam(i+1, cnt+1);
		// 선수 한명을 뽑고 그 선수를 뽑은 상황에서 재귀적을 다음 선수 찾기 
		// makeTeam(i+1, cnt+1)으로 호출할 경우 for문 내부의 if문 실행을 하나 줄일 수 있다. 
		visit[i] = false;
	}
}

int main(){
	scanf("%d", &N);
	
	// 입력 
	for(int i=0; i<N; i++){
		for(int j=0; j<N; j++){
			scanf("%d", &S[i][j]);
		}
	}
	// 능력치합의 차 최소값 구하기
	makeTeam(0,0);
	printf("%d", minS);
	
	return 0;
}

##

주어지는 선수의 수는 최대 20명이므로,

능력치를 저장할 배열 S[20][20];

이 선수를 뽑았는지 체크하는 배열 visit[20] = {false, };

각 팀의 능력치 합 teamStart=0, teamLink=0;

능력치 합의 차 최솟값을 저장할 minSum = 987654321; 으로 초기화.

Start팀에 갈 선수 N/2명만 뽑으면 Link팀 선수들은 자동으로 나머지 선수들이 된다.

'BOJ' 카테고리의 다른 글

BOJ 9461번 :: 파도반 수열  (0) 2019.11.29
BOJ 1904번 :: 01타일  (0) 2019.11.29
BOJ 1003번 :: 피보나치 함수  (0) 2019.11.28
BOJ 2748번 :: 피보나치수 2  (0) 2019.11.28
BOJ 14888번 :: 연산자 끼워넣기  (0) 2019.11.28

+ Recent posts