开始没用二进制优化果断TLE啊,我还以为是我写的不对,后来一百度明白了,学习了一下二进制详细解释看下面
初始化分两种情况
1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w] = -INF;
2、如果不需要正好装满 f[0~v] = 0;
多重背包问题要求很简单,就是每件物品给出确定的件数,求
可得到的最大价值
多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用
分解成若干个件数的集合,这里面数字可以组合成任意小于等于C
的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可
以用数字的二进制形式来解释
比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以
组合成任意小于等于7 的数,而且每种组合都会得到不同的数
15 = 1111 可分解成 0001 0010 0100 1000 四个数字
如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成
7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13
的数,虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种
思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。
下面是不带二进制的,这是TLE的
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
int value,num;
} q[2000];
int f[2500000+5];
int main()
{
int n,m;
while(scanf("%d %d",&n,&m))
{
if(n==0&&m==0)
break;
for(int i=1; i<=n; i++)
scanf("%d",&q[i].value);
int total=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&q[i].num);
total+=q[i].value*q[i].num;
}
total=min(m,total);
memset(f,0,sizeof(f));
for(int i=1; i<=n; i++)
{
if(q[i].value>total)
continue;
for(int k=0; k<=q[i].num; k++)
{
for(int p=total; p>=q[i].value; p--)
f[p]=max(f[p],f[p-q[i].value]+q[i].value);
}
}
int s=0;
for(int i=1; i<=total; i++)
if(f[i]==i)
s++;
printf("%d\n",s);
}
return 0;
}
下面是加上二进制以后的
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
int value,num;
}q[200000];
int v[2000000],f[200000];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m),n||m)
{
for(int i=0;i<n;i++)
scanf("%d",&q[i].value);
for(int i=0;i<n;i++)
scanf("%d",&q[i].num);
int cnt=0;
for(int i=0;i<n;i++)
{
int k=1;
while(k<q[i].num)
{
v[cnt++]=q[i].value*k;
q[i].num-=k;
k*=2;
}
k=q[i].num;
v[cnt++]=q[i].value*k;
}
memset(f,0,sizeof(f));
for(int i=0;i<cnt;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+v[i]);
int s=0;
for(int i=1;i<=m;i++)
if(f[i]==i)
s++;
printf("%d\n",s);
}
return 0;
}
下面是看了别人的据说是模板性质的:
#include<iostream>
#include<stdio.h>
using namespace std;
int dp[100010];//注意数组大小
int value[2000],num[2000];
int n,m;
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
void ZeroOnePack(int value,int weight)
{
int i;
for(i=m;i>=value;i--)
dp[i]=max(dp[i],dp[i-value]+weight);
}
void CompletePack(int value,int weight)
{
int i;
for(i=value;i<=m;i++)
dp[i]=max(dp[i],dp[i-value]+weight);
}
void MultiplePack(int value,int weight,int num)
{
if(value*num>=m) //转化为完全背包
CompletePack(value,weight);
else //二进制优化
{
int k=1;
while(k<=num)
{
ZeroOnePack(k*value,k*weight);
num-=k;
k<<=1;
}
ZeroOnePack(num*value,num*value);
}
}
int main()
{
while(scanf("%d %d",&n,&m))
{
if(n+m==0)
break;
int i;
for(i=1;i<=m;i++)
dp[i]=-10000000; //复制为最小
dp[0]=0;
for(i=0;i<n;i++)
scanf("%d",&value[i]);
for(i=0;i<n;i++)
scanf("%d",&num[i]);
for(i=0;i<n;i++)
MultiplePack(value[i],value[i],num[i]); //多重背包
int ans=0;
for(i=1;i<=m;i++) //统计
{
if(dp[i]>0)
ans++;
}
printf("%d\n",ans);
}
return 0;
}