题目链接:
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;
}