본문 바로가기
알고리즘/백준

[Java] BOJ 17471번 게리맨더링

by 컴공맨 2021. 5. 30.
 

17471번: 게리맨더링

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

www.acmicpc.net


풀이

DFS를 사용해서 1번 선거구와 2번 선거구로 나누고 연결을 시켜 만약 연결이 안 된 지역이 있거나 모든 지역이 하나의 선거구로 이루어져 있다면 불가능한 방법이므로 이 경우를 제외한 인구의 최솟값을 구하게 하여 해결했습니다.

이때, 인구의 최솟값은 양수로 출력되야하므로 abs 즉, 절대값을 사용했습니다.


코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class Main {
	public static int N, minPop;
	public static int[] populations, adjCnt;
	public static boolean[] isConnected;
	public static List<Integer>[] adjMatrix;
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder("");
		StringTokenizer st = null;
		
		N = Integer.parseInt(br.readLine());
		
		populations = new int[N + 1];
		adjCnt = new int[N + 1];
		adjMatrix = new ArrayList[N + 1];
		
		st = new StringTokenizer(br.readLine(), " ");
		for (int i = 1; i <= N; ++i) {
			adjMatrix[i] = new ArrayList<Integer>();
			populations[i] = Integer.parseInt(st.nextToken());
		}
		
		for (int i = 1; i <= N; ++i) {
			st = new StringTokenizer(br.readLine(), " ");
			
			adjCnt[i] = Integer.parseInt(st.nextToken());
			for (int j = 0; j < adjCnt[i]; ++j) {
				adjMatrix[i].add(Integer.parseInt(st.nextToken()));
			}
		}
		
		minPop = Integer.MAX_VALUE;
		go("", 0);
		
		if (minPop == Integer.MAX_VALUE) {
			System.out.println(-1);
		}
		else {
			System.out.println(minPop);			
		}
	}
	
	public static void go(String s, int cnt) {
		if (s.length() == N) {
			int aPopulation = 0;
			int bPopulation = 0;
			
			for (int i = 1; i <= N; ++i) {
				int section = s.charAt(i - 1) - '0';
				
				if (section == 1) {
					aPopulation += populations[i];
				}
				else if (section == 2) {
					bPopulation += populations[i];
				}
			}
			
			// 각 선거구는 적어도 하나의 구역을 포함해야한다.
			if (aPopulation == 0 || bPopulation == 0) {
				return;
			}
			
			isConnected = new boolean[N + 1];
			// 제일 처음 1이 나오는 위치
			for (int i = 1; i <= N; ++i) {
				int start = s.charAt(i - 1) - '0';
				
				if (start == 1) {
					isConnected[i] = true;
					connect(i, s);
					break;
				}
			}

			// 제일 처음 2가 나오는 위치
			for (int i = 1; i <= N; ++i) {
				int start = s.charAt(i - 1) - '0';
				
				if (start == 2) {
					isConnected[i] = true;
					connect(i, s);
					break;
				}
			}
			
			// 연결되지않은 점이 하나라도 존재하면 불가능한 방법
			// 즉, 같은 선거구이지만 연결되지않는 구역이 존재
			for (int i = 1; i <= N; ++i) {
				if (!isConnected[i]) {
					return;
				}	
			}
			
			int result = Math.abs(aPopulation - bPopulation);
			
			minPop = (minPop > result) ? result : minPop;
			
			return;
		}
		
		go(s + "1", cnt + 1);
		go(s + "2", cnt + 1);
	}
	
	public static void connect(int start, String s) {
		for (int i = 0; i < adjMatrix[start].size(); ++i) {
			int section = adjMatrix[start].get(i);
			
			if (!isConnected[section] && s.charAt(start - 1) == s.charAt(section - 1)) {
				isConnected[section] = true;
				connect(section, s);
			}
		}
	}
}

 

pyo7410/Algorithm

1일 1커밋을 목표로! Contribute to pyo7410/Algorithm development by creating an account on GitHub.

github.com

 

'알고리즘 > 백준' 카테고리의 다른 글

[Java] BOJ 5557번 1학년  (0) 2021.06.01
[Java] BOJ 15683번 감시  (0) 2021.05.31
[Java] BOJ 1600번 말이 되고픈 원숭이  (0) 2021.05.28
[Java] BOJ 14502번 연구소  (0) 2021.05.27
[Java] BOJ 16985번 Maaaaaaaaaze  (0) 2021.05.27