具体内容见背包九讲(3)
相关题目:hdu 1171 2844 1059/poj1014 2191 (没做:poj 2392 poj1276)
hdu 2844
大意:有不同价值的硬币,每种价值硬币有一定数量个。求用这些硬币可以组成的钱的种数是多少。
则判断条件不在是 :if( f[i] < f[i-v] + w) ··· 而是 if(f[i] == 0 && f[i - v] != 0) sum++
代码:
//是求可能组成<m的钱数的可能数
#include<iostream>
#include<string.h>
#define size 100010
using namespace std;
int f[size];
int n,m,sum;
void ZeroOnePack(int v)
{
for(int i=m;i>=v;i--)
if(f[i]==0 && f[i-v]!=0) f[i]=1,sum++;
}
void MultiplePack(int v,int no)
{
if(v*no>=m)
{
for(int i=v;i<=m;i++)
if(f[i]==0 && f[i-v]!=0) f[i]=1,sum++;
}
else
{
int k=1;
while(k<no)
{
ZeroOnePack(k*v);
no-=k;
k*=2;
}
ZeroOnePack(no*v);
}
return;
}
int main()
{
int v[110],no[110];
while(scanf("%d%d",&n,&m)!=EOF && n && m)
{
for(int i=0;i<n;i++) scanf("%d",&v[i]);
for(int i=0;i<n;i++) scanf("%d",&no[i]);
memset(f,0,sizeof(f));
f[0]=1; sum=0;
for(int i=0;i<n;i++)
{
MultiplePack(v[i],no[i]);
}
printf("%d\n",sum);
}
return 0;
}
hdu 2191 比较朴素的多重背包解法:
#include<iostream>
#include<string.h>
using namespace std;
int f[110];
int v[110],w[110],no[110];
int n,m;
void ZeroOnePack(int v,int w)
{
for(int i=n;i>=v;i--)
if(f[i]<f[i-v]+w) f[i] = f[i-v]+w;
}
void MultiplePack(int v,int w,int no)
{
if(v*no>=n)
{
for(int i=v;i<=n;i++) if(f[i]<f[i-v]+w) f[i] = f[i-v]+w;
}
int k=1;
while(k<no)
{
ZeroOnePack(v*k,k*w);
no-=k;
k*=2;
}
ZeroOnePack(v*no,no*w);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(f,0,sizeof(f));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&v[i],&w[i],&no[i]);
}
for(int i=0;i<m;i++) MultiplePack(v[i],w[i],no[i]);
int max=0;
for(int i=n;i>=0;i--)
if(f[i]>max) max=f[i];
printf("%d\n",max);
}
return 0;
}