티스토리 뷰
17471번: 게리맨더링
선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.
www.acmicpc.net
💡
1. 선거구 나누기
2. 선거구 유효한지 확인
3. 선거구가 유효할 때 인구 차이 비교
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int N, min=Integer.MAX_VALUE;
static int[] people; // 구역 별 인구
static boolean[] section; // true : 선거구 A, false : 선거구 B
static int[][] path; // 간선 유무
static ArrayList<Integer> a, b;
static boolean[] isVisited;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
// 0 dummy
people = new int[N+1];
path = new int[N+1][N+1];
section = new boolean[N+1];
// 구역 별 인구
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i=1; i<=N; i++) {
people[i] = Integer.parseInt(st.nextToken());
}
// 구열 별 간선 정보
for(int i=1; i<=N; i++) {
st = new StringTokenizer(br.readLine());
int num = Integer.parseInt(st.nextToken());
for(int j=0; j<num; j++) {
int temp = Integer.parseInt(st.nextToken());
path[i][temp] = 1;
path[temp][i] = 1;
}
}
// 선거구 나누고 min값 찾으러~~~ 0은 dummy니까 1구역부터 시작
sub(1);
// min값 변동 없을 경우 선거구를 나눌 수 없으므로 -1 출력
if(min==Integer.MAX_VALUE) System.out.println(-1);
else System.out.println(min);
}
// 로직
static void sub(int tgtIdx) {
if(tgtIdx == N+1) {
// 초기화
a = new ArrayList<>();
b = new ArrayList<>();
isVisited = new boolean[N+1];
// 선거구 나눠 넣기
for(int i=1; i<=N; i++) {
if(section[i]) a.add(i);
else b.add(i);
}
// 한쪽으로 몰리면 선거구 나뉜 것 X
if(a.size()==0 || b.size()==0) return;
// A, B 각 구역 내 이동 가능한지 확인
goA(a.get(0));
goB(b.get(0));
// min값 비교
min = Math.min(min, cal());
return;
}
section[tgtIdx] = true;
sub(tgtIdx+1);
section[tgtIdx] = false;
sub(tgtIdx+1);
}
// 두 선거구의 인구 차이 계산
static int cal() {
// isVisited에 false가 있으면 각 구역 내 이동할 수 없다는 뜻이므로 선거구 유효 X
for(int i=1; i<N+1; i++) {
if(!isVisited[i]) return Integer.MAX_VALUE;
}
// 선거구 별 인구 수
int aSum=0, bSum=0;
for(int i=0; i<a.size(); i++) {
aSum += people[a.get(i)];
}
for(int i=0; i<b.size(); i++) {
bSum += people[b.get(i)];
}
// 인구 차이 return
return Math.abs(aSum - bSum);
}
// 선거구 A 내 이동 가능 여부 확인
static void goA(int s) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(s);
isVisited[s] = true;
while(!queue.isEmpty()) {
int tmp = queue.poll();
for(int i=0; i<a.size(); i++) {
if(path[tmp][a.get(i)] == 1 && !isVisited[a.get(i)]) {
queue.offer(a.get(i));
isVisited[a.get(i)] = true;
}
}
}
}
// 선거구 B 내 이동 가능 여부 확인
static void goB(int s) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(s);
isVisited[s] = true;
while(!queue.isEmpty()) {
int tmp = queue.poll();
for(int i=0; i<b.size(); i++) {
if(path[tmp][b.get(i)] == 1 && !isVisited[b.get(i)]) {
queue.offer(b.get(i));
isVisited[b.get(i)] = true;
}
}
}
}
}
|
cs |
'알고리즘 > 백준' 카테고리의 다른 글
[JAVA] 백준 11729번 (0) | 2021.12.16 |
---|---|
[JAVA] 백준 11659번 (0) | 2021.12.13 |
[JAVA] 백준 14891번 (0) | 2021.03.16 |
[JAVA] 백준 14501번 (0) | 2021.03.10 |
[JAVA] 백준 11653번 (0) | 2021.03.03 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 11659
- 신규아이디추천
- Regex
- 조합
- 재귀
- 제네릭
- 15686
- 4796
- 프로그래머스
- 백준
- CS
- 래퍼 클래스
- 구간 합 구하기
- generic
- Wrapper Class
- 게리맨더링
- 순열
- 하노이 탑
- Stack
- 디자인 패턴
- 알고리즘
- gof
- 와일드카드
- java
- 백트래킹
- recursion
- OOP
- 11729
- BFS
- 2529
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
글 보관함