Optimal Coin Change(揹包)
阿新 • • 發佈:2018-12-20
題目大意:
給你一筆錢,你有n個面值的硬幣,問兌換這筆錢用多少個硬幣,讓硬幣數量最少(若有多組答案,輸出儘可能使用面額小的錢幣)
題解:
完全揹包+路徑輸出
dp[i]代表兌換面值為i的錢需要的最少硬幣數量
對於第i個硬幣,用還是不用(完全揹包的思想)
dp[j+a[i]]=min(dp[j+a[i]],dp[j]+1)
然後因為要記錄第幾個硬幣用幾個,所以再開一個數組c[i][j]表示兌換面值為i的錢,第j個硬幣用了幾個
注意可能有些人會覺得題目要求讓硬幣數量最少,但是輸出的時候又有一個要求是如果有多個解,輸出儘可能使用面值小的硬幣的方案,什麼意思呢
就像第三個樣例
43 5 1 2 21 40 80
答案是1 1 0 1 0
但我還可以 1 0 2 0 0
但這樣顯然1 1 0 1 0這組方案使用了更小的面值小的硬幣,所以答案是它
這種選擇就體現在if(dp[j+a[i]]>=dp[j]+1) 這個等於號上,如果使用了更多面值小的硬幣,那麼剩餘的金額一定更大,所以一定後更新到
#include<bits/stdc++.h> #include<cstring> #define ll long long using namespace std; #define INF 0x3f3f3f3f int a[20]; int dp[2010]; int c[2010][20]; int main() { //freopen("input.txt","r",stdin); int n,v; while(~scanf("%d%d",&v,&n)) { for(int i=1;i<=n;++i) scanf("%d",&a[i]); memset(dp,INF,sizeof(dp)); memset(c,0,sizeof(c)); dp[0]=0; for(int i=1;i<=n;++i) for(int j=0;j<=v;++j) if(j+a[i]<=v) { if(dp[j+a[i]]>=dp[j]+1) { dp[j+a[i]]=dp[j]+1; for(int k=1;k<=n;++k) { c[j+a[i]][k]=c[j][k]; } c[j+a[i]][i]++; } } if(dp[v]==INF) puts("-1"); else { for(int i=1;i<n;++i) printf("%d ",c[v][i]); printf("%d\n",c[v][n]); } } return 0; }