뚱땅뚱땅

[문제] 백준 17471번 게리맨더링 본문

알고리즘/백준

[문제] 백준 17471번 게리맨더링

양순이 2021. 4. 10. 17:13
728x90

www.acmicpc.net/problem/17471

 

17471번: 게리맨더링

선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.

www.acmicpc.net

내 풀이

 

부분집합

public class BOJ_17471 {
	static int N;
	static int[] people;
	static int min;
	static ArrayList<ArrayList<Integer>> list;

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		N = Integer.parseInt(in.readLine());

		people = new int[N + 1]; // 1 based
		StringTokenizer st = new StringTokenizer(in.readLine(), " ");
		for (int i = 1; i <= N; i++) {
			int pp = Integer.parseInt(st.nextToken());
			people[i] = pp;
		}
		// init list
		list = new ArrayList<>();
		for (int i = 0; i <= N; i++) {
			list.add(new ArrayList<>());
		}
		for (int i = 1; i <= N; i++) {
			st = new StringTokenizer(in.readLine(), " ");
			int cnt = Integer.parseInt(st.nextToken());
			for (int j = 0; j < cnt; j++) {
				int node = Integer.parseInt(st.nextToken());
				list.get(i).add(node);
				list.get(node).add(i);
			}
		}
        // 모든 인구 수 
		int totalPeople = 0;
		for(int i=1;i<=N;i++) {
			totalPeople += people[i];
		}
		min = totalPeople;
        
		subset(1, new boolean[N + 1]);
		// 최소값이 모든 인구 수라는 건, 구역을 못나눴다는 의미
		if(min == totalPeople) System.out.println(-1);
		else System.out.println(min);

	}
// 부분집합
	static void subset(int cnt, boolean[] isSelected) {
		if (cnt == N + 1) {
			// 선택한거 : isSelected의 true false로 나눠짐
			boolean[] visited = new boolean[cnt];
			int check = 0;
			for (int i = 1; i < cnt; i++) {
				if (!visited[i]) {
					// i 번 노드에서 시작해서 구역 내 연결되었는지 확인
					dfs(i, visited, isSelected);
					check++;
				}
			}
			// 두 곳이 연결되어 있다면
			if (check == 2) {
				int sum1 = 0, sum2 = 0;
				for (int i = 0; i < cnt; i++) {
					if (isSelected[i])
						sum1 += people[i];
					else
						sum2 += people[i];
				}
				int diff = Math.abs(sum1 - sum2);
				min = Math.min(min, diff);
			}
			return;
		}

		isSelected[cnt] = true;
		subset(cnt + 1, isSelected);

		isSelected[cnt] = false;
		subset(cnt + 1, isSelected);

	}

	// 구역 내 점들이 다 연결되어있는지
	static void dfs(int idx, boolean[] visited, boolean[] isSelected) {
		if (idx > N)
			return;

		visited[idx] = true;
		for (int i = 1; i <= N; i++) {
			if (!visited[i] && isSelected[i] == isSelected[idx] && list.get(idx).contains(i)) {
				dfs(i, visited, isSelected);
			}
		}
	}
}
728x90
Comments