알고리즘 공부/문제 풀이
[JAVA] 백준 17471 게리맨더링
valid_ming
2021. 10. 6. 11:28
https://www.acmicpc.net/problem/17471
17471번: 게리맨더링
선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.
www.acmicpc.net



import java.util.*;
import java.io.*;
public class Main {
static int N, total=0, min = Integer.MAX_VALUE;
static int[] people;
static ArrayList<Integer>[] graph;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
people = new int[N+1];
graph = new ArrayList[N+1];
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i=1; i<=N; i++) {
int val = Integer.parseInt(st.nextToken());
people[i] = val;
total += val;
graph[i] = new ArrayList<>();
}
for(int i=1; i<=N;i++) {
st = new StringTokenizer(br.readLine());
int cnt = Integer.parseInt(st.nextToken());
while(cnt-->0) {
int val = Integer.parseInt(st.nextToken());
graph[i].add(val);
}
}
for(int i=1; i<=N/2;i++) {
comb(i, 0, 1, new int[N+1]);
}
System.out.println(min==Integer.MAX_VALUE?-1:min);
}
public static void comb(int num, int cnt, int start, int[] select) {
if(cnt==num) {
if(check(select)) {
int sum = 0;
for(int i=1; i<=N; i++) {
if(select[i]==1) {
sum += people[i];
}
}
min = Math.min(min, Math.abs((total-sum)-sum));
}
return;
}
for(int i=start; i<=N; i++) {
select[i] = 1;
comb(num, cnt+1, i+1, select);
select[i] = 0;
}
}
public static boolean check(int[] select) {
boolean[] visit = new boolean[N+1];
for(int i=1; i<=N; i++) {
if(select[i]==0) {
dfs(visit, select, i, 0);
break;
}
}
for(int i=1; i<=N; i++) {
if(select[i]==1) {
dfs(visit, select, i, 1);
break;
}
}
for(int i=1; i<=N; i++) {
if(visit[i]==false) return false;
}
return true;
}
public static void dfs(boolean[] visit, int[] select, int cur, int part) {
visit[cur] = true;
for(int i=0;i<graph[cur].size(); i++) {
int next = graph[cur].get(i);
if(!visit[next] && select[next]==part) dfs(visit, select, next, part);
}
}
}