传送门:hdu 2844 coins
题目大意
给定商品种类n和背包容量m以及对应的价值/容量和数量,求组合成不大于背包容量m有多少种可能。
解题思路
这是一个多重背包的题目,价值等于重量。我们根据每种硬币的价值和数量进行判断是转换为完全背包还是01背包。当一种硬币的(数量*价值)大于背包的总容量的时候,也就是相当于在不大于容量m的情况下该种物品满足完全背包的定义所以对于这一种物品来说使用完全背包的思想来求解,当不满足上面的情况就用优化后的01背包进行求解。
AC代码
#include<stdio.h>
#include<string.h>
int a[102],c[102],dp[100005];
int max(int a,int b)
{
return a>b?a:b;
}
void CompletePack(int v,int w,int m) //完全背包
{
for(int j=v; j<=m; j++)
dp[j]=max(dp[j],dp[j-v]+w);
}
void ZeroOnePack(int v,int w,int m) //01背包
{
for(int j=m; j>=v; j--)
dp[j]=max(dp[j],dp[j-v]+w);
}
void MultiPack(int v,int w,int m,int c) //多重背包
{
if(v*c>=m) //体积乘以数量大于总体积,说明不能完全装完,相当于有无穷件,用完全背包
CompletePack(v,w,m);
else //可以装完,用01背包
{
int k=1;
while(k<c) //二进制优化
{
ZeroOnePack(k*v,k*w,m);
c-=k;
k*=2;
}
ZeroOnePack(c*v,c*w,m);
}
}
int main()
{
int n,i,j,m,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
for(i=0; i<n; i++)
scanf("%d",&a[i]); //a[i]既是物体的体积,又是物体的价值
for(i=0; i<n; i++)
scanf("%d",&c[i]); //c[i]是物体的数量
memset(dp,0,sizeof(dp));
for(i=0; i<n; i++)
{
MultiPack(a[i],a[i],m,c[i]);
}
int count=0; //计数
for(i=1; i<=m; i++)
if(dp[i]==i) //可以组合且不用找钱
count++;
printf("%d\n",count);
}
return 0;
}