알고리즘 일지

EPIC Institute of Technology Round Summer 2024 (Div. 1 + Div. 2) D. World is Mine 본문

알고리즘 풀이

EPIC Institute of Technology Round Summer 2024 (Div. 1 + Div. 2) D. World is Mine

황현석 2024. 7. 20. 19:04

 

 

문제 링크

 

Problem - D - Codeforces

 

codeforces.com

 

 

문제 풀이

 

평소에 그냥 딱 하고 풀리던 Dp문제들과 다르게 조금 오래걸려서 풀이를 쓰면서 익숙해지려고 한다. 왜 풀리는지 살짝 이해가 안 돼서 써보면서 나도 이해하려고 한다.

 

일단 Alice 는 케이크를 무조건 가중치가 적은 것부터 먹는 게 유효한 전략이다.

따라서, 배열의 값들을 잘 압축하고, 갯수를 세서 재정렬한다. 즉, {4, 6, 1, 3} 이와 같이, 가중치가 낮은 순으로 정렬해서, 개수만 나는 담았다.

 

그럼 Bob이 Alice를 방해하는 전략이 중요하다. 근데, 전략이 유효한 전략이 없어서, 다이나믹 프로그래밍으로 모든 경우의 수를 적절하게 시행해야 한다.

 

이 시행방법을 잘못 찾고 있었는데, dp테이블에 아무것이나 정의하다 보니까, 딱 들어맞는 걸 발견하게 되었다.

 

$dp[i][j]$ 를 i번째 케이크까지 Alice 가 먹든 안 먹든 했을 때, bob이 j번 케이크를 먹을 수 있을 때의 Alice가 먹은 케이크 개수 중 최솟값이다.

 

i번째 가중치를 가진 케이크까지 왔을 때, bob이 먹어야 할지, 안먹어야 할 지 결정해야 한다. 근데 이때, i번째 가중치를 가진 케이크를 Alice가 먹지 못하게 하려면, bob이 그 케이크의 개수를 다 먹어야 하기 때문에, 값 j도 필요하게 되었다.

 

$$dp[i][j] = \min(dp[i-1][j-1] + 1, dp[i-1][j+W[i]])$$

$$dp[1][1] = 1$$

$dp[1][1] = 1$ 인 이유는, 첫 번째 케이크는 Alice가 무조건 먹고 시작하기 때문이다.

#include<bits/stdc++.h>

typedef long long lint;
using namespace std;

int nums[5050], dp[5050][5050];

typedef pair<int, int> pt;
vector<int> vc;

void solve () {
    int N; cin >> N;

    fill(nums, nums+5050, 0);
    vc.clear();

    for (int i=0;i<N+30;i++) {
        for (int j=0;j<N+30;j++) {
            dp[i][j] = 1e9;
        }
    }

    dp[1][1] = 1;

    for (int i=0;i<N;i++) {
        int c; cin >> c;
        vc.push_back(c);
        nums[c]++;
    }

    sort(vc.begin(), vc.end());
    vc.erase(unique(vc.begin(), vc.end()), vc.end());

    for (int i=1;i<vc.size();i++) {
        for (int j=0;j<=N;j++) {
            dp[i+1][j+1] = min(dp[i+1][j+1], dp[i][j] + 1);
            if (j-nums[vc[i]] >= 0) {
                int &x = dp[i+1][j-nums[vc[i]]];
                x = min(x, dp[i][j]);
            }
        }
    }

    int ans = 1e9;
    for (int i=0;i<=N;i++) ans = min(ans, dp[vc.size()][i]);
    cout << ans << '\n';
}

int main () {
    cin.tie(0);ios_base::sync_with_stdio(0);
    int _; cin >> _;
    while(_-->0) solve();
}

'알고리즘 풀이' 카테고리의 다른 글

BOJ 1146 - 지그재그 서기  (0) 2024.08.06
BOJ 9616 - 홀수 정사각형  (0) 2024.08.03
BOJ 1514 - 자물쇠  (0) 2024.07.18
BOJ 23054 - 누텔라 트리 (Hard)  (0) 2024.05.21
BOJ 17139 - 초라기와 쿼리  (0) 2024.04.09