ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 게리맨더링 - 17471
    알고리즘 문제 풀이/백준 2021. 4. 13. 16:40

    문제설명

     

    www.acmicpc.net/problem/17471

     

    17471번: 게리맨더링

    선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.

    www.acmicpc.net

     

     

    기본아이디어

    주어진 지점들을 두 분류로 나누고, 각 지점들의 값들의 합의 차이 중 최소값을 찾는 문제이다. 여기서 중요한 점은 두 분류로 나눴을 때 각각의 점들이 다 이어져 있어야 합니다.

     

    주어지는 N값이 작기 때문에 dfs, bfs 탐색으로 해도 된다는 생각이 들었고, 그래서 조합으로 가능한 경우를 다 만든 다음에 bfs탐색으로 연결이 되어있는지 확인하는 방법을 사용했습니다.

     

    PS. 너무 많이 틀려서 반례를 많이 찾아봤는데 여기서 많이 도움이 됐습니다.www.acmicpc.net/board/view/54133

     

    글 읽기 - C#) 어디서 틀렸는지 감이 안잡힙니다. + 시도해 본 케이스들

    댓글을 작성하려면 로그인해야 합니다.

    www.acmicpc.net

     

    구현코드

    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
    public static void main(String[] args) throws IOException {
            input = new BufferedReader(new StringReader(src));
            N = Integer.parseInt(input.readLine());
            population = new int[N+1];
            StringTokenizer st = new StringTokenizer(input.readLine());
            total_sum = 0;
            for(int i = 1; i <= N; i++) {
                population[i] = Integer.parseInt(st.nextToken());
                total_sum += population[i];
            }
            map = new ArrayList[N+1];
            for(int i = 1; i <= N; i++)
                map[i] = new ArrayList<Integer>();
            for(int i = 1; i <= N; i++){
                st = new StringTokenizer(input.readLine());
                int cnt = Integer.parseInt(st.nextToken());
                for(int j= 0; j < cnt; j++)
                    map[i].add(Integer.parseInt(st.nextToken()));
            }
            visited = new boolean[N+1];
            min = Integer.MAX_VALUE;
            dfs(1,00);
     
     
            System.out.println(min==Integer.MAX_VALUE?-1:min);
        }
        static int N;
        static int[] population;
        static List<Integer>[] map;
        static int min, total_sum;
        static boolean[] visited;
        static void dfs(int idx, int cnt, int sum){
            if(chk1() && chk2()) {
                int diff = Math.abs(total_sum - sum * 2);
                if (diff < min) {
                    min = diff;
                }
            }else if(cnt == N)
                return;
     
            for(int i = idx; i <= N; i++){
                if(!visited[i]){
                    visited[i] = true;
                    dfs(i+1, cnt+1, sum + population[i]);
                    visited[i] = false;
                }
            }
        }
     
        static boolean chk1(){
            int start = 0;
            boolean[] chkArr = new boolean[N+1];
            for(int i = 1; i <= N; i++){
                if(!visited[i]) {
                    chkArr[i] = true;
                    start = i;
                }
            }
            if(start == 0)
                return false;
            Queue<Integer> queue = new LinkedList<>();
            queue.add(start);
            while(!queue.isEmpty()){
                int temp = queue.poll();
                chkArr[temp] = false;
                for(int next: map[temp]){
                    if(chkArr[next]){
                        queue.add(next);
                    }
                }
            }
            for(boolean ok : chkArr){
                if(ok)
                    return false;
            }
            return true;
        }
     
        static boolean chk2(){
            int start = 0;
            boolean[] chkArr = new boolean[N+1];
            for(int i = 1; i <= N; i++){
                if(visited[i]) {
                    chkArr[i] = true;
                    start = i;
                }
            }
            if(start == 0)
                return false;
            Queue<Integer> queue = new LinkedList<>();
            queue.add(start);
            while(!queue.isEmpty()){
                int temp = queue.poll();
                chkArr[temp] = false;
                for(int next: map[temp]){
                    if(chkArr[next]){
                        queue.add(next);
                    }
                }
            }
            for(boolean ok : chkArr){
                if(ok)
                    return false;
            }
            return true;
        }
     
    cs

     

    정리, 기억할 내용

    1. 처음 아이디어에서 dfs, bfs 어떤걸 사용할지 잘 정하자.

    2. 백준에서 질문검색에서 반례 잘 찾아보자.

     

     

    '알고리즘 문제 풀이 > 백준' 카테고리의 다른 글

    [백준] 카드 구매하기 - 11052  (0) 2021.04.14
    [백준] 경비원 - 2564  (0) 2021.04.13
    [백준] 퇴사 - 14501번  (0) 2021.04.12
    [백준] 소수 구하기 - 1929번  (0) 2021.03.11
    [백준] DFS와 BFS - 1260번  (0) 2021.03.11

    댓글

Designed by Tistory.