넘치게 채우기

[BOJ] 1082 - 방 번호 본문

PS/BOJ

[BOJ] 1082 - 방 번호

riveroverflow 2025. 5. 19. 09:29
반응형

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

BOJ - 방 번호

문제 유형: 다이나믹 프로그래밍, 그리디

문제 난이도: Gold III

시간 제한: 1초

메모리 제한: 128MB

 

문제

스타트링크가 입주한 사무실은 방 번호를 직접 정할 수 있다. 방 번호를 정하려면 1층 문방구에서 파는 숫자를 구매해야 한다. 숫자를 구매하기 위해 준비한 금액은 M원이다.

문방구에서 파는 숫자는 0부터 N-1까지이고, 각 숫자 i의 가격은 Pi이다. 문방구에서는 같은 숫자를 여러 개 구매할 수 있고, 문방구는 매우 많은 재고를 보유하고 있기 때문에, 항상 원하는 만큼 숫자를 구매할 수 있다. 방 번호가 0이 아니라면 0으로 시작할 수 없다.

예를 들어, N = 3, M = 21, P0 = 6, P1 = 7, P2 = 8이라면, 만들 수 있는 가장 큰 방 번호는 210이다. 최대 M원을 사용해서 만들 수 있는 가장 큰 방 번호를 구해보자.

 

입력

첫째 줄에 N이 주아진다. 둘째 줄에는 공백으로 구분된 P0, ..., PN-1이 주어진다. 마지막 줄에는 M이 주어진다.

 

출력

첫째 줄에 최대 M원을 사용해서 만들 수 있는 가장 큰 방 번호를 출력한다. 적어도 하나의 숫자를 살 수 있는 입력만 주어진다.

 

풀이

dp[i] = i원이 남았을 때의 최선의 suffix로 한다.

처음에는 0이 오면 안되기에, 9~1을 붙여서 dfs를 시도한다.

현재 남은 예산으로 아무것도 살 수 없다면, ""를 리턴하여 종료시키고, 아니라면, 그리디하게 9~1순서로 재귀 호출시켜서 가장 큰 suffix를 만들어낸다.

dp테이블에 저장시키며 리턴한다.

 

숫자는 long long형으로도 못 담는다. 즉, 문자열 숫자로 구성하고 대소비교를 해줘야 한다.

a가 b보다 크거나 같은지 확인하는 ge함수를 참조하자. 

 

코드

C++

#include <bits/stdc++.h>

using namespace std;

int n, minimum;
vector<string> numtostr = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

bool ge(const string& a, const string& b) {
    if (a.size() < b.size()) return false;
    if (a.size() > b.size()) return true;
    for (int i = 0; i < a.size(); i++) {
        if (a[i] < b[i]) return false;
        if (a[i] > b[i]) return true;
    }

    return true;
}

string solve(int remain, vector<int>& p, vector<string>& dp) {
    if (remain < minimum) {
        return "";
    }

    if (dp[remain] != ".") {
        return dp[remain];
    }

    string res = "";
    for (int i = n - 1; i >= 0; i--) {
        if (remain >= p[i]) {
            string temp = numtostr[i] + solve(remain - p[i], p, dp);
            if (ge(temp, res)) {
                res = temp;
            }
        }
    }
    return dp[remain] = res;
}

int main(int argc, char* argv[]) {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    int m;
    cin >> n;
    vector<int> p(n);
    for (auto& i : p) cin >> i;
    cin >> m;
    minimum = *min_element(p.begin(), p.end());

    vector<string> dp(m + 1, ".");

    string res = "";
    for (int i = n - 1; i > 0; i--) {
        if (m >= p[i]) {
            string temp = numtostr[i] + solve(m - p[i], p, dp);
            if (ge(temp, res)) {
                res = temp;
            }
        }
    }
    if (res == "") {
        cout << "0\n";
    } else {
        cout << res << "\n";
    }

    return 0;
}
반응형

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

[BOJ] 31963 - 두 배  (0) 2025.05.22
[BOJ] Auto-Complete  (0) 2025.05.20
[BOJ] 3066 - 브리징 시그널  (0) 2025.05.18
[BOJ] 25823 - 조합의 합의 합  (0) 2025.05.17
[BOJ] 23845 - 마트료시카  (0) 2025.05.15