http://acm.hdu.edu.cn/showproblem.php?pid=1085
1、2、5 三种面值的硬币各有num[0]、num[1]、num[2] 个,问不能用它们组合支付的最小的钱数?
两种方法:①多重背包(需用二进制优化,否则超时)、②直接推算
多重背包代码:
#pragma warning (disable:4786)
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int dp[10000];
int Sumc;
//二进制优化后的多重背包
void multi_pack(int cost,int num){
int sum=0;
int k=1;
int j;
while(sum<num){
if(k>num-sum)
k=num-sum;
for(j=Sumc;j>=cost*k;j--){
if(dp[j-cost*k]!=0){
dp[j]=1;
}
}
sum+=k;
k+=k;
}
}
int main()
{
int num[4],i,j;
int cost[3]={1,2,5};
while(1)
{
scanf("%d%d%d",&num[0],&num[1],&num[2]);
Sumc=num[0]+num[1]*2+num[2]*5;
if(Sumc==0)
break;
//背包的容量为所有硬币面值加起来的和+1
Sumc+=1;
memset(dp,0,sizeof(dp));
dp[0]=1;
for(i=0;i<3;i++){
if(num[i]>0)
multi_pack(cost[i],num[i]);
}
for(i=1;i<=Sumc;i++)
if(dp[i]==0)
break;
printf("%d\n",i);
}
return 0;
}
直接推算代码:
#pragma warning (disable:4786)
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int main()
{
int num[4],i,j,sum;
int cost[3]={1,2,5};
while(1)
{
scanf("%d%d%d",&num[0],&num[1],&num[2]);
if(!num[0]&&!num[1]&&!num[2])
break;
//因为2^0、2^1...2^n 能组成<=2^(n + 1) - 1 的所有正整数
//所以a个1和b个2能组成<=2*b+a的所有正整数
if(num[0]!=0){
sum=num[1]*2+num[0];
if(sum<4)
printf("%d\n",sum+1);
else{
if(num[2]>0)
printf("%d\n",sum+5*num[2]+1);
else printf("%d\n",sum+1);
}
}
else printf("1\n");
}
return 0;
}