코딩테스트/문제

[BOJ] 20303번: 할로윈의 양아치

스키(ski) 2024. 4. 2. 14:14
문제 내용

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

 

풀이 시간

1시간

풀이 과정

여러개의 그룹들을 구하는 것이어기 때문에 유니온-파인드가 떠올랐다.

이후 문제를 풀면서 최대값을 구하는 로직을 작성 해지만 오답 -> 문제를 제대로 안읽엇다.

- 여러 그룹들이어도 인원의 총 합이 K이하면 가능했다.

가능한 모든 경우의 수를 확인하기 위해 그룹들의 subset을 구하려고 했다. -> 시간초과 

 

-시간 초과의 원인

1. 그룹을 만드는 기존 코드의 시간 복잡도 => O(N^2) -> O(N)으로 줄여야 했다.

     => Map을 사용하여 구현 했다.

2. subset로직의 시간초과

    => 시간 복잡도를 줄이기 위해 Knapsack을 응용해서 풀이.

정답 코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;


public class Main {
    static int N,M,K;
    static int[] candy;
    static int[] parent;
    static Map<Integer,int[]> group;

    public static void main(String[] args) throws Exception {
        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());

        candy=new int[N+1];
        parent=new int[N+1];
        st=new StringTokenizer(br.readLine());

        for(int i=1;i<=N;i++) {
            candy[i] = Integer.parseInt(st.nextToken());
            parent[i] = i;
        }

        for(int i=0;i<M;i++){
            st=new StringTokenizer(br.readLine());
            int a=Integer.parseInt(st.nextToken());
            int b=Integer.parseInt(st.nextToken());

            union(a,b);
        }

        group=new HashMap<>();

        for(int i=1;i<=N;i++){
            int root=find(i);

            int[] stat=group.getOrDefault(root,new int[2]);
            stat[0]++;
            stat[1]+=candy[i];

            group.put(root,stat);
        }

        int[] dp=new int[K];

        for(int x:group.keySet()){
            int[] stat=group.get(x);

            if(stat[0]>K) continue;

            for(int i=K-1;i>=stat[0];i--){
                dp[i]=Math.max(dp[i],dp[i-stat[0]]+stat[1]);
            }
        }
        int result=0;
        for(int i=0;i<K;i++){
            result=Math.max(result,dp[i]);
        }

        System.out.println(result);
    }

    static boolean union(int a,int b){
        int aRoot=find(a);
        int bRoot=find(b);

        if(aRoot==bRoot) return false;

        parent[bRoot]=aRoot;

        return true;
    }

    static int find(int x){
        if(parent[x]==x) return x;
        return parent[x]=find(parent[x]);
    }
}

 

 

'코딩테스트 > 문제' 카테고리의 다른 글

[BOJ] 2146번: 다리 만들기  (0) 2024.04.08
[BOJ] 16946번: 벽 부수고 이동하기 4  (0) 2024.04.03
[BOJ] 12026번: BOJ거리  (0) 2024.04.02
[백준] 15652번: N과 M (4)  (0) 2023.12.20
[백준] 9663번: N-Queen  (0) 2023.12.20