题意:有现今cash,和n种钱币,每种钱币有ni个,价值为di,求各种钱币组成的不超过cash的最大钱数.......
思路:二进制拆分转化为01背包,或者转化为完全背包都是可以的。
反思:这个题目我wa两次,是应为我把判断cash==0||n==0放得太前,以致于后面的数据木有输入
wa代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[110000],t[30000],s[2000][2];
int main()
{
int cash,n;
while(scanf("%d%d",&cash,&n)>0)
{
if(cash==0||n==0) //错在这里,放的太前
{
printf("0
");
continue;
}
int cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&s[i][0],&s[i][1]);
int k=1;
while(s[i][0]-k>0)
{
t[cnt++]=k*s[i][1];
s[i][0]-=k;
k*=2;
}
t[cnt++]=s[i][0]*s[i][1];
}
memset(dp,0,sizeof(dp));
for(int i=0;i<cnt;i++)
{
for(int j=cash;j>=t[i];j--)
if(dp[j]<dp[j-t[i]]+t[i])
dp[j]=dp[j-t[i]]+t[i];
}
printf("%d
",dp[cash]);
}
return 0;
}
ac代码,二进制拆分:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[110000],t[30000],s[2000][2];
int main()
{
int cash,n;
while(scanf("%d%d",&cash,&n)>0)
{
int cnt=0;
//memset(t,0,sizeof(t));
for(int i=1;i<=n;i++)
{
scanf("%d%d",&s[i][0],&s[i][1]);
int k=1;
if(s[i][0]==0||s[i][1]==0)
continue;
while(s[i][0]-k>0)
{
t[cnt++]=k*s[i][1];
s[i][0]-=k;
k*=2;
}
t[cnt++]=s[i][0]*s[i][1];
}
memset(dp,0,sizeof(dp));
for(int i=0;i<cnt;i++)
{
for(int j=cash;j>=t[i];j--)
if(dp[j]<dp[j-t[i]]+t[i])
dp[j]=dp[j-t[i]]+t[i];
}
printf("%d
",dp[cash]);
}
return 0;
}
ac代码,转换为完全背包:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[110000],num[100100],s[2000][2];
int main()
{
int cash,n;
while(scanf("%d%d",&cash,&n)>0)
{
int cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&s[i][0],&s[i][1]);
}
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
memset(num,0,sizeof(num));
for(int j=s[i][1];j<=cash;j++)
if(dp[j]<dp[j-s[i][1]]+s[i][1]&&num[j-s[i][1]]<s[i][0])
{
dp[j]=dp[j-s[i][1]]+s[i][1];
num[j]=num[j-s[i][1]]+1;
}
}
printf("%d
",dp[cash]);
}
return 0;
}