01背包
洛谷p1048采药
01背包对于每一个物品,在当前的s可装下当前物品时比较装下该物品的总价值和不装该物品的价值。
(经典题+1)pascal也做过,省空间的做法如下
#include<bits/stdc++.h>
using namespace std;
int m,t,s[1010]={0},ma=0;
struct plant
{
int time,value;
};
plant p[110];
int main()
{
scanf("%d%d",&t,&m);
for(int i=1;i<=m;i++)scanf("%d%d",&p[i].time,&p[i].value);
for(int j=1;j<=m;j++)//枚举每棵草药
for(int i=t;i>=p[j].time;i--)s[i]=max(s[i],s[i-p[j].time]+p[j].value);//从后往前避免草药重复选择
for(int i=1;i<=t;i++)if(s[i]>ma)ma=s[i];//其实可以直接输出s[t],emmm...
printf("%d",ma);
return 0;
}
洛谷p1466集合
一个计算装满01背包的方案数的问题,和递推有相似之处(似乎就是递推?——蒟蒻的猜测)
#include<bits/stdc++.h>
using namespace std;
int n,t,sum=0;
long long s[10000]={0};
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)sum+=i;
if(sum%2)
{
printf("0\n");
return 0;
}
sum=sum/2;
s[0]=1;
for(int j=1;j<=n;j++)
for(int i=sum;i>=j;i--)s[i]=s[i]+s[i-j];
printf("%lld",s[sum]/2);//输出方案要/2!老是卡在这种地方真是该做俯卧撑了
return 0;
}
完全背包
洛谷p1616疯狂地采药
和01背包很相似,不多讲
#include<bits/stdc++.h>
using namespace std;
int m,t;
long long s[100010]={0},ma=0;
struct plant
{
int time,value;
};
plant p[10010];
int main()
{
scanf("%d%d",&t,&m);
for(int i=1;i<=m;i++)scanf("%d%d",&p[i].time,&p[i].value);
for(int j=1;j<=m;j++)
for(long long i=p[j].time;i<=t;i++)s[i]=max(s[i],s[i-p[j].time]+p[j].value);//和01背包相比,只是换了一下循环的起始和结束
for(long long i=1;i<=t;i++)if(s[i]>ma)ma=s[i];
printf("%lld",ma);
return 0;
}
洛谷p1474货币系统
也是完全背包,和1446对应
#include<bits/stdc++.h>
using namespace std;
int v,n,t,sum=0,a[30]={0};
long long s[10010]={0};
int main()
{
scanf("%d%d",&v,&n);
for(int i=1;i<=v;i++)scanf("%d",&a[i]);
s[0]=1;
for(int j=1;j<=v;j++)
for(int i=a[j];i<=n;i++)s[i]=s[i]+s[i-a[j]];
printf("%lld",s[n]);
return 0;
}
洛谷p2725邮票
完全背包+1,但是常数太大也不行。
部分TLE版本
#include<bits/stdc++.h>
using namespace std;
int k,n,sum=0,a[30]={0};
long long s[2000010][2]={0},t=0;//s[i][0]存是否可以组成i,s[i][1]存最少邮票数
long long mi(long x,long y)
{
if(y==0)return x;
if(x<y)return x;
else return y;
}
int main()
{
scanf("%d%d",&k,&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
s[0][0]=1;s[0][1]=0;
for(int j=1;j<=n;j++)
for(int i=a[j];i<=10000*k;i++)
if(s[i-a[j]][0]>0)s[i][0]=1,s[i][1]=mi(s[i-a[j]][1]+1,s[i][1]);
for(int i=1;i<=10000*k;i++)if(s[i][1]>k||s[i][0]==0){t=i-1;break;}
printf("%lld",t);
return 0;
}
AC版本
#include<bits/stdc++.h>
using namespace std;
int k,n,sum=0,a[100]={0},t;
long long s[2000010];
long long mi(long x,long y)
{
if(y==0)return x;
if(x<y)return x;
else return y;
}
int main()
{
scanf("%d%d",&k,&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=10000*k;i++)s[i]=233;//初始化减少了一个判断,减少了数组的一维
s[0]=0;
for(int j=1;j<=n;j++)
for(int i=a[j];i<=10000*k;i++)
if(s[i-a[j]]+1<=k)s[i]=mi(s[i-a[j]]+1,s[i]);//常数大概少了一半......
for(int i=1;i<=10000*k;i++)if(s[i]>k){t=i-1;break;}
printf("%d",t);
return 0;
}
多重背包
洛谷p1776宝物筛选
先把一个物品拆成了多个物品试着做,光荣TLE
#include<bits/stdc++.h>
using namespace std;
int n,w,s[400010]={0},ma=0,t=0;
struct sub
{
int wei,num,val;
};
sub a[10010];
struct subject
{
int weight,value;
};
subject b[100010];
int main()
{
scanf("%d%d",&n,&w);
for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i].val,&a[i].wei,&a[i].num);
for(int i=1;i<=n;i++)
for(int j=1;j<=a[i].num;j++)b[++t].weight=a[i].wei,b[t].value=a[i].val;//物品拆分
for(int j=1;j<=t;j++)
for(int i=w;i>=b[j].weight;i--)s[i]=max(s[i],s[i-b[j].weight]+b[j].value);
for(int i=1;i<=w;i++)if(s[i]>ma)ma=s[i];
printf("%d",ma);
return 0;
}
然后就是多重背包的重点了,任意正整数n都可以被拆分为1,2,4,...,2^(k-1),n[i]-2^k+1(k是满足n[i]-2^k+1>0的最大整数),这些数可以组成1到n中任意一个数。
#include<bits/stdc++.h>
using namespace std;
int n,w,s[400010]={0},ma=0;
struct sub
{
int wei,num,val;
};
sub a[10010];
struct subject
{
int weight,value;
};
subject t;
int main()
{
scanf("%d%d",&n,&w);
for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i].val,&a[i].wei,&a[i].num);
for(int i=1;i<=n;i++)
{
int k=1;
while(k<=a[i].num)//玄学拆分
{
t.weight=a[i].wei*k;
t.value=a[i].val*k;
a[i].num-=k;
k=k<<1;
for(int i=w;i>=t.weight;i--)s[i]=max(s[i],s[i-t.weight]+t.value);//直接01背包形式处理
}
if(a[i].num>0)
{
t.weight=a[i].wei*a[i].num;t.value=a[i].val*a[i].num;
for(int i=w;i>=t.weight;i--)s[i]=max(s[i],s[i-t.weight]+t.value);//多余部分处理
}
}
for(int i=1;i<=w;i++)if(s[i]>ma)ma=s[i];
printf("%d",ma);
return 0;
}