题意:有n个硬币A[i]表示第i个硬币的价值,C[i]表示第i个硬币的数量
求有多少种组合情况的值在1~m之中
多重背包解决:定义dp[i]为把能装下i价值的抽屉在硬币的组合情况下能装下的最大的价值
显然dp[i]<=i,所以当dp[i]==i时就代表有一种硬币组合情况
代码实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m;
int dp[100005];
struct Money
{
int value;
int num;
}money[100005];
int main()
{
int ans,i,j,k,jj;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)break;
for(i=0;i<n;i++)
scanf("%d%d",&money[i].value,&money[i].num);
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
{
if(money[i].value*money[i].num>=m)
{
for(j=money[i].value;j<=m;j++)//完全背包
dp[j]=max(dp[j],dp[j-money[i].value]+money[i].value);
}
else
{
k=1;int ncount=money[i].num;
while(k<=ncount)
{
for(j=m;j>=money[i].value;j--)//01背包
dp[j]=max(dp[j],dp[j-money[i].value*k]+money[i].value*k);
ncount-=k;
k*=2;
}
for(j=m;j>=money[i].value;j--)//01背包
dp[j]=max(dp[j],dp[j-money[i].value*ncount]+money[i].value*ncount);
}
}
ans=0;
for(i=1;i<=m;i++)
if(dp[i]==i)ans++;
printf("%d\n",ans);
}
return 0;
}