#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF 987654321
using namespace std;

bool graph[11][11]; //인접 행렬
int population[11]; //인구수
int N; //구역 개수

bool used[11];
bool check[11];
int ret = INF;

void isConnect() {

	//used = true 인 구역 연결 확인
	memmove(check, used, sizeof(check));
	int target = -1;
	for (int i = 1; i <= N; i++) {
		if (check[i]) {
			target = i; 
			break;
		}
	}
	if (target == -1) return;
	queue<int> q;
	q.push(target);
	while (!q.empty()) {
		int front = q.front();
		check[front] = false;
		q.pop();
		for (int i = 1; i <= N; i++) {
			if (graph[front][i] && check[i]) {
				q.push(i);
			}
		}
	}
	bool is_conn = true;
	for (int i = 1; i <= N; i++) {
		if (check[i]) is_conn = false;
	}

	//연결 안된 구역 있다면 return
	if (!is_conn) return;


	//used = false 인 구역 연결 확인
	memmove(check, used, sizeof(check));
	target = -1;
	for (int i = 1; i <= N; i++) {
		if (!check[i]) {
			target = i;
			break;
		}
	}
	queue<int> q2;
	q2.push(target);
	while (!q2.empty()) {
		int front = q2.front();
		check[front] = true;
		q2.pop();
		for (int i = 1; i <= N; i++) {
			if (graph[front][i] && !check[i]) {
				q2.push(i);
			}
		}
	}
	is_conn = true;
	for (int i = 1; i <= N; i++) {
		if (!check[i]) is_conn = false;
	}

	//연결 안된 구역 있으면 return
	if (!is_conn) return;

	//두 구역이 모두 각각 연결상태라면 인구수 차이 비교
	int sum1 = 0;
	int sum2 = 0;
	for (int i = 1; i <= N; i++) {
		if (used[i]) {
			sum1 += population[i];
		}
		else {
			sum2 += population[i];
		}
	}
	int diff = abs(sum1 - sum2);
	ret = min(ret, diff);

}

void dfs(int idx, int toPick) {
	if (toPick == 0) {
		isConnect();
		return;
	}
	for (int i = idx; i <= N; i++) {
		if (!used[i]) {
			used[i] = true;
			dfs(i, toPick - 1);
			used[i] = false;
		}
	}

}

int main() {
	
	scanf("%d", &N);
	for (int i = 1; i <= N; i++) {
		scanf("%d", &population[i]);
	}
	for (int i = 1; i <= N; i++) {
		int cnt;
		scanf("%d", &cnt);
		for (int j = 0; j < cnt; j++) {
			int temp;
			scanf("%d", &temp);
			graph[i][temp] = 1;
			graph[temp][i] = 1;
		}
	}

	for (int i = 1; i <= N; i++) {
		dfs(0, i);
	}
	if (ret == INF) {
		printf("%d\n", -1);
	}
	else{
		printf("%d\n", ret);
	}

	return 0;
}

 

1. 선거구를 나누는 방법은 최대 10C1 + 10C2 + ... + 10C9 + 10C10 이라서 2046가지이다.

 

2. dfs() 함수가 선거구를 선택하는 조합을 찾고, isConnect() 함수로 나눠진 구역의 연결 상태를 확인, 인구 수 차이를 비교한다.

 

3. isConnect() 함수에서 연결 여부를 판단할 때 bfs를 사용했다. dfs()로 한 가지 경우를 찾았을 때 used값이 true인 구역과 false인 구역으로 나누어진다. 이 때 true인 구역끼리의 연결 여부를 bfs로 체크하고, false 인 구역끼리의 연결 여부도 bfs로 체크한다. 그리고 각각의 구역이 연결되어있는 경우 인구수 차이를 계산해서 현재 ret 값보다 작다면 ret를 갱신한다.

 

* 연결 여부를 체크할 수 있는 다른 방법이 있는지 생각해 볼 것.

+ Recent posts