引进题目
超市零元购,你有一个背包,你可以把超市里的东西放入背包带走,但是背包的容积有限,给出每个超市物品的价值以及它的体积,求最大价值是多少
很显然,这是一个最基础的 01背包 模型,常规做法使用 动态转移方程 解决,这方法固然很好,但是想,正常的思维是怎么想到用这种方法? 对于我来说,我是不可能自己想到的(当然不包括个别大佬-·-·-)
所以我们尝试用其它的较为简单的方法求解
这里分享两种,这两种方法在题解中我是没有见到过的,是自己探究出的
第一种 递归算法
递归的优点是可以简洁明了(就是大家都可以理解的),缺点也显而易见吗,会超时!!!
这种方法只适用于小的数据,大数据要算到猴年马月、、、
#include <stdio.h>
#include <stdlib.h>
int n,w,ww[101],vv[101],ans;
int putin()
{
scanf("%d%d",&n,&w);
for(int i=1;i<=n;i++) scanf("%d",&ww[i]);
for(int i=1;i<=n;i++) scanf("%d",&vv[i]);
}
int cy(int x,int o)
{
if(x>n || o<=0) return 0;
else
{
if(o-ww[x]>=0)
{
if(cy(x+1,o-ww[x])+vv[x]>cy(x+1,o)) return cy(x+1,o-ww[x])+vv[x];
else return cy(x+1,o);
}
else return cy(x+1,o);
}
}
int putout()
{
printf("%d",ans);
}
int main()
{
freopen("D:/text1.in","r",stdin);
putin();
ans=cy(1,w);
putout();
}
稍微看一看就知道是怎么个事
重头在第二种
我们知道,对于一个物品,只有两种情况,一种是放,一种是不放,于是我们可以枚举所有的方法,例如有三个物品abc,我们可以枚举以下情况
Y表示放,N表示不放
方案/物品 | a | b | c |
1 | Y | Y | Y |
2 | Y | Y | N |
3 | Y | N | Y |
4 | Y | N | N |
5 | N | Y | Y |
6 | N | N | Y |
7 | N | Y | N |
8 | N | N | N |
可以知道,当有n个物品时,共有2的n次方个方案;
于是,我们就可以利用两个二维数组来分别储存总剩余容积和总已有价值,具体代码如下
#include <stdio.h>
#include <stdlib.h>
int n,w[10],v[10],ww[1001][1001],vv[1001][1001]={0},W,t=-1,p,l[1];
int input()
{
scanf("%d%d",&n,&W);
ww[0][0]=W;
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++) scanf("%d",&v[i]);
}
int cf(int kk)
{
int y=1;
// printf("kk=%d ",kk);
for(int i=1;i<=kk;i++)
{
y=y*2;
}
// printf("y=%d \n",y);
return y;
}
int zx()
{
for(int i=1;i<=n;i++)
{
p=cf(i);
for(int j=1;j<=p;j++)
{
if(ww[i-1][j]>=w[i] && j%2==1)
{
vv[i][j]=vv[i-1][(j+1)/2]+v[i];
ww[i][j]=ww[i-1][(j+1)/2]-w[i];
}
else
{
vv[i][j]=vv[i-1][j/2];
ww[i][j]=ww[i-1][j/2];
}
}
}
}
int output()
{
int oi;
for(int i=1;i<=p;i++) if(vv[n][i]>t) t=vv[n][i];
printf("result=%d\n",t);
}
int main()
{
// freopen("D:/text1.in","r",stdin);
input();
zx();
output();
}
该程序难点就在于找到正确的数组的位置,例如下列数据:
6 100
40 38 38 36 27 45
3868 1252 1536 634 3016 4555
在函数 zx 中数组的表示就较为复杂
不难发现,二维数组的空间浪费太多太多了,于是我们想办法使用一维数组实现
将后面的数据覆盖至前面,可以看出,用从后往前的数据赋值更方便于我们的空间利用
#include <stdio.h>
#include <stdlib.h>
int n,W,w[101],v[101],ww[101]={0},vv[101]={0},p;
int input()
{
scanf("%d%d",&n,&W);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++) scanf("%d",&v[i]);
ww[1]=W;
}
int cif(int x)
{
int y=1;
for(int i=1;i<=x;i++) y*=2;
return y;
}
int zhuangx()
{
for(int i=1;i<=n;i++)
{
p=cif(i);
for(int j=p;j>=1;j--)
{
if(j%2==0)
{
vv[j]=vv[j/2];
ww[j]=ww[j/2];
}
else
{
if(ww[(j+1)/2]>=w[i])
{
vv[j]=vv[(j+1)/2]+v[i];
ww[j]=ww[(j+1)/2]-w[i];
}
else
{
vv[j]=vv[(j+1)/2];
ww[j]=ww[(j+1)/2];
}
}
}
}
}
int output()
{
int t=-1;
for(int i=1;i<=p;i++) if(vv[i]>t) t=vv[i];
printf("result=%d\n",t);
}
int main()
{
freopen("D:/text1.in","r",stdin);
input();
zhuangx();
output();
}