https://www.acmicpc.net/problem/17471
17471번: 게리맨더링
선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.
www.acmicpc.net
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
// 구역의 수
static int N;
// 구역의 인구
static int[] population;
// 인접 행렬
static boolean[][] adjMatrix;
// 선거구 인구 차이의 최솟값
static int minDiff = Integer.MAX_VALUE;
// 구역 체크 true: A, false: B
static boolean[] isAreaA;
// 구역 연결 여부 확인 시 사용
static boolean[] validCheck;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
// 구역의 인구 입력 받기
population = new int[N + 1];
st = new StringTokenizer(br.readLine());
for (int i = 1; i <= N; i++) {
population[i] = Integer.parseInt(st.nextToken());
}
// 간선 정보 입력
adjMatrix = new boolean[N + 1][N + 1];
// n: 인접한 구역의 수
int n = 0, to = 0;
for (int from = 1; from <= N; from++) {
st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
for (int i = 0; i < n; i++) {
to = Integer.parseInt(st.nextToken());
adjMatrix[from][to] = true;
}
}
// 선거 구역 나누기
// N / 2: 1개 뽑는 조합과 N-1개 뽑는 조합의 인구 차의 값은 동일하므로
for (int i = 1; i <= N / 2; i++) {
isAreaA = new boolean[N + 1];
combination(0, 1, i);
}
System.out.println(minDiff == Integer.MAX_VALUE ? -1 : minDiff);
}
// r: 뽑는 개수
private static void combination(int cnt, int start, int r) {
// 선거구 선택 완료한 경우
if (cnt == r) {
// 선거구 연결 여부 확인
if (!isVaild()) {
return;
}
// 선거구 인구 차이 계산
int diff = getDiff();
// 최솟값 갱신
minDiff = Math.min(minDiff, diff);
return;
}
for (int i = start; i <= N; i++) {
// A 선거구인 경우
if (isAreaA[i]) {
continue;
}
// A 선거구로 선택
isAreaA[i] = true;
combination(cnt + 1, i, r);
// 다음 선택 위해 되돌리기
isAreaA[i] = false;
}
}
private static boolean isVaild() {
// 선거구 연결 확인
validCheck = new boolean[N + 1];
// A 구역 확인
for (int i = 1; i <= N; i++) {
// A 구역의 정점일 경우
if (isAreaA[i]) {
dfs(i, true);
break;
}
}
// B 구역 확인
for (int i = 1; i <= N; i++) {
// B 구역의 정점일 경우
if (!isAreaA[i]) {
dfs(i, false);
break;
}
}
// 모두 방문했는지 확인
for (int i = 1; i <= N; i++) {
// 방문하지 못한 곳이 있다면 연결되지 않은 것이므로 false
if (!validCheck[i]) {
return false;
}
}
// 모두 방문했다면 연결되어 있으므로 true
return true;
}
private static void dfs(int from, boolean area) {
validCheck[from] = true;
for (int to = 1; to <= N; to++) {
// 이동가능하고 같은 선거구이고 방문하지 않은 곳이라면
if (adjMatrix[from][to] && isAreaA[to] == area && !validCheck[to]) {
dfs(to, area);
}
}
}
private static int getDiff() {
int aPop = 0;
int bPop = 0;
for (int i = 1; i <= N; i++) {
// A구역이라면
if (isAreaA[i]) {
aPop += population[i];
}
// B구역이라면
else {
bPop += population[i];
}
}
return Math.abs(aPop - bPop);
}
}
'Baekjoon Online Judge > Java' 카테고리의 다른 글
[Baekjoon Online Judge] 2234 - 성곽 / Java (0) | 2021.11.03 |
---|---|
[Baekjoon Online Judge] 16956 - 늑대와 양 / Java (0) | 2021.10.26 |
[Baekjoon Online Judge] 4179 - 불! / Java (0) | 2021.10.01 |
[Baekjoon Online Judge] 1194 - 달이 차오른다, 가자. / Java (0) | 2021.09.29 |
[Baekjoon Online Judge] 4485 - 녹색 옷 입은 애가 젤다지? / Java (0) | 2021.09.29 |