팀을 정할 때에는 팀원의 수가 다 찰 때 까지 백트래킹을 통해 1팀에서 한명씩 뽑아나간다.
팀원 (0,1) 과 (1,0) 을 뽑는 경우는 같은 경우기 때문에, 반복문의 시작 인덱스를 직전 호출에서 넘겨주어야 한다.
1팀의 팀원 수가 다 찼다면, 나머지 팀원들을 2팀으로 지정한다.
행렬이 대칭이 아니기 때문에, 팀의 능력치는 각 팀별로 2명씩 뽑았을 때 가능한 모든 조합들을 인덱싱해서 더해야 한다.
#include <iostream>
using namespace std;
int n, team_n, answer = 10e8;
int info[20][20];
bool visited[20];
int team[2][10];
int power(int t) // t 로 주어지는 팀의 능력치를 반환
{
int ret = 0;
for(int i = 0 ; i < team_n - 1 ; i++) // 팀을 2중반복문으로 돌리면서 능력치를 다 더함
{
for(int j = i + 1 ; j < team_n ; j++)
{
ret += info[team[t][i]][team[t][j]];
ret += info[team[t][j]][team[t][i]];
}
}
return ret;
}
void check(int start, int size) // 백트래킹
{
if(size == team_n)
{
for(int i = 0, idx = 0 ; i < n ; i++) // 팀1 이 구해졌기 때문에, 팀2 를 그에 맞게 구하고
{
if(visited[i] == false)
team[1][idx++] = i;
}
int value = abs(power(0) - power(1)); // 두 팀 능력치의 차이를 구해서
if(value < answer) answer = value; // 최솟값 갱신
return;
}
for(int i = start + 1 ; i < n ; i++) // 팀1 의 멤버들을 뽑는 과정
{
if(visited[i] == false)
{
visited[i] = true;
team[0][size] = i; // 팀1 의 멤버목록에 추가해주고
check(i, size + 1); // 재귀호출
visited[i] = false;
}
}
}
int main(void)
{
cin >> n;
team_n = n / 2;
for(int r = 0 ; r < n ; r++)
for(int c = 0 ; c < n ; c++)
cin >> info[r][c];
check(-1, 0);
cout << answer << endl;
}