• 문제 링크
17471번: 게리맨더링
선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.
www.acmicpc.net
• 풀이 과정
각 구역의 번호를 인덱스로 지정하는 value 배열에 인구 값을 입력받고,
인접행렬에 각 구역과 인접한 구역의 정보를 입력받아 인접할 시 1로 저장한다.
구역을 둘로 나누기 위해 한 구역은 subset 배열의 true, 다른 한 구역은 false 로 나타내며,
재귀 함수(recur) 를 통해 구역을 둘로 나누는 모든 경우의 수를 각 구역의 값의 합을 누적하며 구한다.
경우의 수가 구해지면, 매개변수를 true 또는 false 로 전달받는 isConnected 함수로
해당 경우의 두 구역이 문제에 조건에 부합하는 지 검사한다.
먼저 검사하는 구역에 포함하는 시작점을 찾고,(subset[i] == flag)
같은 구역에 속하며, 구역끼리 인접하고 방문하지 않은 구역
(subset[i] == flag && map[node][i] == 1 && !visit[i]) 을 탐색해나가며 이동 가능한 구역을 방문 처리한다.
이 후 같은 구역에 속하지만 방문한 적이 없는, 즉 연결되지 않는 구역이 존재한다면 false 를 반환,
이 조건까지 통과할 경우 true 를 반환한다.
이렇게 두 구역이 문제의 조건에 맞게 나뉘어 졌다면, 두 구역의 인구차의 최솟값을 갱신한다.
만약 최솟값이 갱신되었다면 해당 값을, 아니면 -1 을 정답으로써 출력한다.
• 풀이 코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int n, total;
static int[] value;
static int[][] map;
static boolean[] subset;
static int min = Integer.MAX_VALUE;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
n = Integer.parseInt(br.readLine());
value = new int[n + 1];
map = new int[n + 1][n + 1];
subset = new boolean[n + 1];
st = new StringTokenizer(br.readLine());
for (int i = 1; i <= n; i++) {
value[i] = Integer.parseInt(st.nextToken());
total += value[i];
}
for (int i = 1; i <= n; i++) {
st = new StringTokenizer(br.readLine());
int m = Integer.parseInt(st.nextToken());
for (int j = 0; j < m; j++)
map[i][Integer.parseInt(st.nextToken())] = 1;
}
recur(1, 0);
bw.write((min == Integer.MAX_VALUE ? -1 : min) + "\n");
bw.flush();
}
private static void recur(int idx, int sum) {
if (idx > n) {
if (isConnected(true) && isConnected(false))
min = Math.min(min, Math.abs(sum - (total - sum)));
return;
}
subset[idx] = true;
recur(idx + 1, sum + value[idx]);
subset[idx] = false;
recur(idx + 1, sum);
}
private static boolean isConnected(boolean flag) {
Queue<Integer> q = new LinkedList<>();
boolean[] visit = new boolean[n + 1];
for (int i = 1; i <= n; i++) {
if (subset[i] == flag) {
q.offer(i);
visit[i] = true;
break;
}
}
while (!q.isEmpty()) {
int node = q.poll();
for (int i = 1; i <= n; i++) {
if (subset[i] == flag && map[node][i] == 1 && !visit[i]) {
q.offer(i);
visit[i] = true;
}
}
}
for (int i = 1; i <= n; i++) {
if (subset[i] == flag && !visit[i])
return false;
}
return true;
}
}
'Problem Solving > Baekjoon' 카테고리의 다른 글
[백준] 16958 텔레포트 - Brute Force / Java (0) | 2022.09.16 |
---|---|
[백준] 4902 삼각형의 값 - Brute Force / Java (0) | 2022.09.15 |
[백준] 14391 종이 조각 - Brute Force / Java (0) | 2022.09.13 |
[백준] 1107 리모컨 - Brute Force / Java (0) | 2022.09.12 |
[백준] 17299 오등큰수 - Data Structure / Java (0) | 2022.09.11 |
댓글