Skip to main content
  1. Posts/
  2. Algorithm/

BOJ 26969 Bribing Friends

·493 words·3 mins
Jiho Kim
Author
Jiho Kim
달려 또 달려

📝 문제 정보
#

문제 번역
#

Bessie는 “소 유전체학: 다큐멘터리"를 보고 싶지만, 혼자 가고 싶지 않습니다. 불행히도, 그녀의 친구들은 함께 갈 만큼 열정적이지 않습니다! 따라서 Bessie는 친구들이 영화관에 함께 가도록 뇌물을 줘야 합니다. 그녀는 두 가지 뇌물 수단을 가지고 있습니다: 무니(mooney)와 아이스크림 콘입니다.

Bessie는 $N$명 ($1 \le N \le 2000$)의 친구가 있습니다. 하지만 모든 친구가 똑같지는 않습니다! 친구 $i$는 인기도 점수 $P_i$ ($1 \le P_i \le 2000$)를 가지고 있으며, Bessie는 자신과 함께 가는 친구들의 인기도 점수 합을 최대화하고 싶습니다. 친구 $i$는 Bessie가 $C_i$ ($1 \le C_i \le 2000$) 무니를 주면 함께 가려고 합니다. 또한 Bessie가 $X_i$ ($1 \le X_i \le 2000$)개의 아이스크림 콘을 주면 1 무니의 할인을 제공합니다. Bessie는 할인으로 인해 친구가 그녀에게 무니를 주지 않는 한, 한 친구로부터 원하는 만큼 정수 단위의 할인을 받을 수 있습니다.

Bessie는 $A$개의 무니와 $B$개의 아이스크림 콘을 가지고 있습니다 ($0 \le A, B \le 2000$). 그녀가 무니와 아이스크림 콘을 최적으로 사용했을 때 달성할 수 있는 인기도 점수 합의 최댓값을 구하는 것을 도와주세요!

입력
#

첫 번째 줄에는 세 개의 숫자 $N$, $A$, $B$가 주어지며, 각각 친구의 수, Bessie가 가진 무니의 양, 아이스크림 콘의 개수를 나타냅니다.

다음 $N$개의 줄 각각에는 세 개의 숫자 $P_i$, $C_i$, $X_i$가 주어지며, 각각 인기도 ($P_i$), 친구 $i$가 Bessie와 함께 가도록 하는 데 필요한 무니 ($C_i$), 친구 $i$로부터 1 무니 할인을 받는 데 필요한 아이스크림 콘 ($X_i$)을 나타냅니다.

출력
#

Bessie가 무니와 아이스크림 콘을 최적으로 사용했을 때, 함께 가는 친구들의 인기도 점수 합의 최댓값을 출력합니다.

🧐 관찰 및 접근
#

  • 2초에 $O(NAB)$ 8억을 믿어볼까?
    • 아 나이브는 아이스크림 콘을 몇개 줄지를 몰라서 심지어 세제곱도 넘는다 ㅋㅋ
  • 이번에도 BOJ 13448 SW 역량 테스트 문제처럼 좀 그리디하게 생각해보자.
  • 살 소들을 정했다면, $X$가 작은 소들을 먼저 꼬셔서 무니를 할인받는게 이득이다.
    • 잉 이것만해도 세제곱이 보장되는것같다
    • 근데 세제곱이 안돈다 ㅋㅋ
  • 고민해보니, 앞에서는 콘을 열심히 퍼주다가 / 한 친구한테는 섞어서 주다가 / 그뒤부터는 그냥 무니로 사야하는 것 같다
    • 세제곱에서 제곱으로 줄일 수 있겠다!

💻 풀이
#

  • 코드 (C++):

void solve(){
    cin >> N >> A >> B;
    vector<Friend> Frd(N);
    rep(i, 0, N) cin >> Frd[i].P >> Frd[i].C >> Frd[i].X;
    sort(all(Frd), [](Friend &A, Friend &B){
        return A.X < B.X;
    });

    rep(i, 0, N){
        auto [P, C, X] = Frd[i];
        rrep(j, 0, B+1){
            DPprf[i+1][j] = max(DPprf[i+1][j], DPprf[i][j]);
            if(j - X*C < 0) continue;
            DPprf[i+1][j] = max(DPprf[i+1][j], DPprf[i][j - X*C] + P);
        }
    }

    rrep(i, 0, N){
        auto [P, C, X] = Frd[i];
        rrep(j, 0, A+1){
            DPsuf[i][j] = max(DPsuf[i][j], DPsuf[i+1][j]);
            if(j - C < 0) continue;
            DPsuf[i][j] = max(DPsuf[i][j], DPsuf[i+1][j-C] + P);
        }
    }

    int ans = max(DPprf[N][B], DPsuf[0][A]);
    rep(i, 0, N){
        auto [P, C, X] = Frd[i];
        rep(j, 0, B+1){
            int mxDiscount = min(C, j / X);
            int moonie = A - (C - mxDiscount), cones = B - j;
            if(moonie < 0 || cones < 0) continue;
            ans = max(ans, P + DPprf[i][cones] + DPsuf[i+1][moonie]);
        }
    }
    cout << ans;
}
🔒

구현 코드 잠금

아래 쿠팡 링크를 방문하시면 코드가 공개됩니다.
광고 수익이 블로그 운영에 도움이 됩니다 🙏

🛒 쿠팡 방문하고 코드 보기

방문 후 잠금이 자동으로 해제됩니다