/*
多重背包问题:一般化为01背包[逆序]和完全背包[顺序]来求解
多重背包优化:二进制原理。
dp[i]表示:容量为i的背包在限制条件下[硬币的面值和数量]所能获得的最大值
此题中的每个硬币的体积[重量]和价值[面值]是同一个数[a]。
当dp[i]==i时,表示容量为i的背包可以装下价值为i的物品,即相当于能够用所限的
硬币凑足i。最后再扫一遍数组就能得出结果。
*/
#include<iostream>
using namespace std;
const int MAXN=100005;
struct Node
{
int a;
int c;
};
int dp[MAXN];
int mymax(int a,int b)
{
return a>b?a:b;
}
void CompletePack(int w,int m)//完全背包(顺序求解,w即使重量也是价值)
{
for(int i=w;i<=m;i++)
{
dp[i]=mymax(dp[i],dp[i-w]+w);
}
}
void ZeroOnePack(int w,int m)//01背包(逆序求解,w即使重量也是价值)
{
for(int i=m;i>=w;i--)
{
dp[i]=mymax(dp[i],dp[i-w]+w);
}
}
void MultiPack(int w,int c,int m)
{
if(w*c>=m)//面值*数目〉所要凑得面值(相当于有无限多个面值为w的硬币可用)
{
CompletePack(w,m);//多重背包-->完全背包
}
else//否则,多重背包-->01背包
{ //二进制原理转换成01背包求解。
int k=1;
while(c-k>0)
{
ZeroOnePack(w*k,m);
c-=k;
k*=2;
}
ZeroOnePack(w*c,m);//剩下的硬币数目
}
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(!n&&!m)
{
break;
}
int temp=0;//统计能凑齐的数目
Node p[105];
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)//录入面值
{
cin>>p[i].a;
}
for(int i=0;i<n;i++)//录入数目
{
cin>>p[i].c;
}
for(int i=0;i<n;i++)
{
MultiPack(p[i].a,p[i].c,m);
}
for(int i=1;i<=m;i++)//扫描统计
{
if(dp[i]==i)
{
temp++;
}
}
cout<<temp<<endl;
}
return 0;
}
一般将多重背包转换成01背包和完全背包求解。
多重背包问题:二进制原理,单调队列。