【問題描述】
給你一個n種面值的貨幣系統,求組成面值為m的貨幣有多少種方案。
【輸入】
第一行輸入兩個正整數n和m,用空格隔開,分別表示貨幣系統的面值種數和要組成的總面值。
以下n行,每行輸入一個正整數,表示貨幣系統的面值。
【輸出】
一行一個數,表示組成目標面值的方案總數。
【輸入輸出樣例】
money.in |
money.out |
3 10 1 2 5 |
10 |
【數據范圍】
對於100%的數據,n<=100,m<=10000。
乍眼一看:
背包問題的方案總數
對於一個給定了背包容量、物品費用、物品間相互關系(分組,依賴)的背包問題,除了再給定每個物品的價值后求可得到的最大值以外,還可以得到裝滿背包或將背包裝置某一容量的方案總數(這道題就是這樣)。
對於這類改變問法的問題,一般只需要將轉移方程中的max改成sum即可。
例如若每件物品均是01背包中的物品,轉移方程即為f[i][v]=sum{f[i-1][v],f[i-1][v-w[i]]+c[i]},初始條件f[0][0]=1;
事實上,這樣做可行的原因在於狀態轉移方程已經考慮了所有可能的背包組成方案。
對於這道 貨幣系統:
設f[j]表示面值為j的最大方案數,如果f[j-k*a[i]]!=0,則f[j]=f[j]+f[j-k*a[i]],當1<=i<=n,m>=j>=a[i],1<=k<=j/a[i]。
程序
:
#include<iostream> #include<cstdio> using namespace std; int a[10001],n,m; long long f[10005];//注意long long int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } f[0]=1; for(int i=1;i<=n;i++) for(int j=m;j>=a[i];j--)//f[j]表示面值為j的方案最優解。 for(int k=1;k<=j/a[i];k++) f[j]+=f[j-k*a[i]]; cout<<f[m];//表示最優解。 return 0; }