歡迎加入我的 Discord 群組與我討論程式相關的問題!

Posted on 

 by 

 in ,

CSES – Coin Combinations II

評分:1 分,滿分為 5。

題目連結

題意

給 n 個硬幣,問湊出總和 x 有幾種方法,在這題同樣的幾個硬幣不同順序拿會算是同種方法! 使用不同的硬幣組合才會算是不同的方法

解題想法 – DP

狀態

dp[i] 表示總和為 x 的拿法有幾種

轉移

// c 是儲存硬幣的陣列
for j = 0 ~ n-1:
    for i = 1 ~ x:
        dp[i] += dp[i-c[j]]

這題雖然跟上一題轉移式雖然是一樣的,但是計算的順序有所不同。
因為上一題的計算方法,我們是計算每個 sum 要怎麼湊出來,我們可能會算到同種湊法很多次。


我們現在把枚舉硬幣的迴圈放在外面那層,我們每個硬幣就只會跑一次裡面的迴圈,就可以避免到後面重新使用到這個硬幣。所以這樣就一種湊法就不會被算到第二次了。

我們裡面的迴圈 for i = 1 ~ x 是正著跑。假如 dp[3] 的其中一種方法會用到一個 3 的硬幣,跑到 dp[6] 的時候還是可以用到 dp[6-3] (dp[3]),所以一個硬幣可以被用很多次。

而根據題目這也是合法的,所以這樣我們避免了重複計算,也會處理到同一個硬幣要用很多次的 case。

初始條件

dp[0] = 1

總和為 0 的方法有一種,就是都不拿

複雜度: O(n*x)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MOD = 1e9+7;
int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    int n, x;
    cin >> n >> x;
    vector <long long> c(n), dp(x+1);
    for(long long &u : c) {
        cin >> u;
    }
    dp[0] = 1;
    for(int j = 0;j < n;j++){
        for(int i = 1;i <= x;i++){
            if(i-c[j] >= 0){
                dp[i] += (dp[i-c[j]])%MOD;
                dp[i] %= MOD;
            }
        }
    }
    cout << dp[x] << '\n';
}

發表迴響

Blog at WordPress.com.

%d 位部落客按了讚: