티스토리 뷰

알고리즘/백준

[JAVA] 백준 17471번

코딩가딩 2021. 3. 24. 02:29

www.acmicpc.net/problem/17471

 

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
링크
«   2025/05   »
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
글 보관함