할로윈의 양아치(BOJ20303)

2024. 11. 17. 21:58BOJ/DP

문제

이미지 클릭

문제 설명

  • n명의 학생이 존재하고 m개의 친구관계가 주어진다.
  • 친구 관계를 본다면 특정 사람의 사탕을 뺏는 다면 그 사람의 친구의 사탕도 무조건 뺏어야 한다.
  • 만약 사탕을 뺏은 사람의 수가 k를 넘지 않게 해주어야 한다.

문제 해설

  • Union-Find
친구의 관계를 나타내기 위해서 특정 친구를 기준으로 하여서 모두 연결해주어야 한다.
예를 들어, 2-4, 4-5 그리고 5-7의 관계가 있다면 친구 7을 기준으로 2,4,5의 대표 친구를 7로 설정해 준다.(bfs로도 가능함..)
  • 중간 단계
대표 친구를 기준으로 하여서 친구들의 수와 친구들이 가지고 있는 사탕의 개수를 저장해 준다.
  • dp(knapsack)
dp [친구의 수]: 0~k-1명을 체우는 경우의 수를 냅색을 활용하여서 최대를 찾아준다.

최종 코드

#include <bits/stdc++.h>
using namespace std;
long long n, m, k;
vector<long long> parent(30004), d(30004), sum(30004, 0), Size(30004, 0);
vector<long long> dp(30004, 0);
int find(int x) { #find
    if (x == parent[x]) return x;
    return parent[x] = find(parent[x]);
}
void unionSets(int x, int y) { #union
    x = find(x), y = find(y);
    if (x != y) parent[y] = x;
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) parent[i] = i;
    for (int i = 1; i <= n; i++) cin >> d[i];
    for (int i = 1, x, y; i <= m; i++) {
        cin >> x >> y;
        unionSets(x, y); #친구 그룹화하기
    }
    for (int i = 1; i <= n; i++) {
        int p = find(i); #대표 친구(부모)
        sum[p] += d[i]; #사람이 가지는 사탕의 수
        Size[p]+=1; #친구의 수
    }
    for (int i = 1; i <= n; i++) {
        if (Size[i] > 0) {
            for (int j = k - 1; j >= Size[i]; j--) {
                dp[j] = max(dp[j], dp[j - Size[i]] + sum[i]); 
            }
        }
    }
    cout << dp[k - 1]; #k-1명의 최대 사탕개수
}

이미지 클릭

'BOJ > DP' 카테고리의 다른 글

괄호 추가하기3 (BOJ16639)  (0) 2024.11.25
성인 게임 (BOJ 23256)  (2) 2024.11.24
암호코드 (BOJ 2011)  (2) 2024.10.09
올바른 괄호 문자열 (BOJ 3012)  (1) 2024.09.12
ABC (BOJ 12969)  (1) 2024.08.26