題目:
http://acm.swust.edu.cn/#/problem/575/490
題目描述
設有n 種不同面值的硬幣,各硬幣的面值存於數組T[1:n]中。現要用這些面值的硬幣來找錢。可以使用的各種面值的硬幣個數存於數組Coins[1:n]中。 對於給定的1≤n≤10,硬幣面值數組T和可以使用的各種面值的硬幣個數數組Coins,以及錢數m,0≤m≤20001,編程計算找錢m的最少硬幣數。
輸入
第一行中只有1 個整數給出n的值,第2 行起每行2 個數,分別是T[j]和Coins[j]。最後1 行是要找的錢數m。
輸出
最少硬幣數,無解時輸出-1
樣例輸入
3
1 3
2 3
5 3
18
樣例輸出
5
說明:
這道題可以用多重揹包來解決,多重揹包的思路就是一次可以取給定數量個物品的01揹包。不過這道題目將硬幣面值看作體積,然後找出裝滿揹包總體積的最小硬幣個數。故需要將dp數組初始化爲inf,dp[0]的初值賦爲0。至於無解情況,若最終狀態能轉移到dp[sum](sum代表找錢數m),則一定有解。
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
const int inf=0x3f3f3f3f;
int t[maxn],coin[maxn],dp[maxn];
int n,sum;
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>t[i]>>coin[i];
cin>>sum;
for(int i=0;i<maxn;i++){
dp[i]=inf;
}
dp[0]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=coin[i];j++){
for(int k=sum;k>=t[i]*j;k--){
dp[k]=min(dp[k],dp[k-t[i]*j]+j); //枚舉裝k件物品i的狀態轉移
}
}
}
if(dp[sum]==inf){
cout<<-1<<endl;
}else{
cout<<dp[sum]<<endl;
}
return 0;
}