题目链接:
UVA 147 Dollars
题意:
美元基础面额分为100美元,50美元,20美元,10美元,5美元,2美元,1美元以及50美分,20美分,10美分,5美分。1美元等于100美分。输入一个金额(保证是5美分的倍数),问由基础面额组成这个金额有多少种方法?
如:20美分:5美分*4;5美分*2+10美分;10美分*2;20美分。共4种。
分析:
完全背包。每种基础面额只要合法是无限取的。dp[i][j]表示前i种基础面额所能组成j的方法数
初始化:dp为0,但是dp[0][0]=1.
状态转移方程:
dp[i][j]=dp[i][j]+dp[i][j-data[i]];
其中data[i]代表第i种基础面额,因为输入是5美分的倍数,所以可以将基础面额和输入金额都除以5,也就是5美分对应1,10美分对应2。。。1美元对应20,。。。,100美元对应2000,一共11种基础面额。
注意:
- ①:输入的精度问题。
total=(int)(n*100+0.5)/5;
而不是:
total=(int)(n*100)/5;
- ②:要用long long。
//完全背包 176MS 0K
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_VAL=6010;
int data[15]={0,1,2,4,10,20,40,100,200,400,1000,2000};
double n;
int total;
long long dp[MAX_VAL];
int main()
{
freopen("Hin.txt","r",stdin);
//freopen("Hout.txt","w",stdout);
while(~scanf("%lf",&n)){
if(n==0) break;
total=(int)(n*100+0.5)/5;
//printf("total=%d\n",total);
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=11;i++){
for(int j=data[i];j<=total;j++){
dp[j]+=dp[j-data[i]];
//printf("i=%d j=%d dp[j]=%d\n",i,j,dp[j]);
}
}
printf("%6.2f%17lld\n",n,dp[total]);
}
return 0;
}