ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 20303번 : 할로윈의 양아치 - 자바(JAVA)
    알고리즘/백준 2022. 7. 27. 00:01
    728x90

    https://www.acmicpc.net/problem/20303

     

    20303번: 할로윈의 양아치

    첫째 줄에 정수 $N$, $M$, $K$가 주어진다. $N$은 거리에 있는 아이들의 수, $M$은 아이들의 친구 관계 수, $K$는 울음소리가 공명하기 위한 최소 아이의 수이다. ($1 \leq N \leq 30\ 000$, $0 \leq M \leq 100\ 000$,

    www.acmicpc.net

     

    문제 해석

    스브러스는 사탕을 뺏으려고 한다.

    이때 스브러스는 사탕을 뺏을 때 한 아이의 사탕을 뺏으면 그 아이 친구들의 사탕도 모조리 뺏어버립니다.

    이때 K명 이상의 아이들의 뺏지 않으면서 최대로 뺏을 수 있는 사탕의 양을 구하세요

     

    문제 풀이전 설계

    거리에 있는 아이들의 수 N = 30,000

    아이들의 친구 관계 수 M = 100,000

    K = 3,000

     

     

    1. DFS/ BFS /Union Find 어떤것을 쓰던 우선 친구 그룹을 지어줍니다.

     

    2. 친구그룹별로 사탕의 개수와 , 연결되어있는 친구들의 수가 도출됩니다.

     

    3. 이를 토대로 최대 몇 명을 뺏을 수 있는지 탐색합니다.

     

    문제 풀이하면서

    2번까지는 순조롭게 잘 되었습니다.

    이후에 3번을 2중반복문을통해 하면 해결되겠지 하고 제출하니 2%에 틀렸습니다가 나옵니다.

     

    곰곰이 생각해보니 단순히 2개로만 최댓값을 비교하면 안 됩니다.

    만약 3개, 4개를 합쳐서 최댓값이 되는 경우를 생각해보면 오답이 나오는 이유를 알 수 있습니다.

     

    따라서 0-1 배낭 문제처럼 값을 계속 기록해나가면서 최댓값을 경신해나가야 정답을 찾을 수 있습니다.

     

     

    코드

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.*;
    
    public class Main_20303_할로윈의양아치 {
    
        static List<SteelInfo> canSteel = new ArrayList<>();
        static List<ArrayList<Integer>> links = new ArrayList<>();
        static int[] childs;
        static boolean[] visited;
        static int N, M, K;
    
        static class SteelInfo {
            int sum;
            int childCount;
    
            public SteelInfo(int sum, int childCount) {
                this.sum = sum;
                this.childCount = childCount;
            }
    
            @Override
            public String toString() {
                return "SteelInfo{" +
                        "sum=" + sum +
                        ", childCount=" + childCount +
                        '}';
            }
        }
    
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st = new StringTokenizer(br.readLine());
    
            N = Integer.parseInt(st.nextToken());
            M = Integer.parseInt(st.nextToken());
            K = Integer.parseInt(st.nextToken());
    
            childs = new int[N + 1];
            st = new StringTokenizer(br.readLine());
            for (int i = 1; i <= N; i++) {
                childs[i] = Integer.parseInt(st.nextToken());
            }
    
            for (int i = 0; i <= N; i++) {
                links.add(new ArrayList<>());
            }
    
            for (int i = 0; i < M; i++) {
                st = new StringTokenizer(br.readLine());
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());
                links.get(a)
                     .add(b);
                links.get(b)
                     .add(a);
            }
    
            //입력끝, 양방향 연결그래프 생성
    
            visited = new boolean[N + 1];
    
            for (int i = 1; i <= N; i++) {
                if (visited[i]) {
                    continue;
                }
                SteelInfo result = steelCandy(i);
                if (result.childCount < K) {
                    canSteel.add(result);
                }
            }
    
            int size = canSteel.size();
    
    
            int[][] dp = new int[2][K];
    
            for (int i = 0; i < canSteel.size(); i++) {
                SteelInfo now = canSteel.get(i);
                int childCount = now.childCount;
                int sum = now.sum;
    
                for (int j = 0; j < K; j++) {
                    if (j >= childCount && dp[0][j - childCount] + sum > dp[0][j])
                        dp[1][j] = dp[0][j - childCount] + sum;
                    else
                        dp[1][j] = dp[0][j];
                }
                dp[0] = dp[1].clone();
            }
            System.out.println(dp[1][K - 1]);
            
    
        }
    
        private static SteelInfo steelCandy(int childIndex) {
    
            Queue<Integer> bfsQ = new LinkedList<>();
            bfsQ.add(childIndex);
            visited[childIndex] = true;
    
            int sum = 0;
            int count = 0;
            SteelInfo result = null;
            while (!bfsQ.isEmpty()) {
    
                Integer curIndex = bfsQ.poll();
                sum += childs[curIndex];
                count++;
    
                for (Integer cur : links.get(curIndex)) {
                    if (visited[cur]) {
                        continue;
                    }
    
                    bfsQ.add(cur);
                    visited[cur] = true;
                }
            }
            result = new SteelInfo(sum, count);
    
            return result;
    
        }
    }

     

     

     

     

    댓글

Designed by Tistory.