您的位置:首页 > 其它

【背包问题】

2016-03-06 14:36 267 查看

01背包

二维这样写

for (int i=1;i<=m;i++)
for (int j=w[i];j<=t;j++){
a[i][j]=a[i-1][j];
if (j-w[i]>=0)a[i][j]=max(a[i-1][j],a[i-1][j-w[i]]+v[i]);


因为很长时间没写,受一维的影响,一开始写成了这样

for (int i=1;i<=m;i++)
for (int j=w[i];j<=t;j++)
a[i][j]=max(a[i-1][j],a[i-1][j-w[i]]+v[i]);


需要注意的是,a[i][1~w[i]]没值啊没值啊没值啊(是栋栋发现的!栋栋太厉害了!)

for (int i=1;i<=m;i++)
{
for(int j=0;j<w[i];j++)
a[i][j]=a[i-1][j];
for (int j=w[i];j<=t;j++)
a[i][j]=max(a[i-1][j],a[i-1][j-w[i]]+v[i]);
}


这是栋栋改的,所以我要存下来
一维

j是从m循环到w[i](省去判断了,不用担心上面那个问题)

为什么倒着循环?

省略了第一维,在二维数组中,我们是由a[i-1][j-w[i]]更新a[i][j]的

a[j]=max(a[j],a[j-w[i]]+v[i]);

推a[j]需要用到a[j-w[i]],显然j-w[i]<j,如果正着循环,就相当于用a[i][j-w[i]]更新a[i][j]了

for (int i=1;i<=n;i++)
for (int j=m;j>=w[i];j--)
a[j]=max(a[j],a[j-w[i]]+v[i]);


如果要把背包装满呢?

那就把a[0]初始化为0,a[1~n]初始化为-∞。

a[0]相当于装满了容量为0的背包,价值为0,是合法状态。

a[1~n]全是不合法的状态。

在循环过程中,如果a[j-w[i]]是合法的状态,那么a[j]就是合法的状态。

(上面是小敏颜告诉我的)

而对于普通的背包,全部初始为0,就是全都合法。

完全背包

和01背包的区别是一种物品可以放无限次。所以刚才说的倒着循环,就没必要了。

因为既然可以放无限次,就不用考虑上一次到底是放还是没放了。

for (int i=1;i<=m;i++)
for (int j=w[i];j<=t;j++)
a[j]=max(a[j],a[j-w[i]]+v[i]);


多重背包

n种物品,每种有sum[i]件,价值为v[i],代价w[i],装到容量为m的包里使价值最大

拆成01背包

二进制拆分

xp[0]=1;for (int i=1;i<=14;i++) xp[i]=xp[i-1]*2;


这地方注意,xp[0]等于1。

for (int i=1;i<=n;i++){
for (int j=0;j<=14;j++){
if (num[i]<xp[j]) break;
w[++cnt]=w1[i]*xp[j];    v[cnt]=v1[i]*xp[j];
num[i]-=xp[j];
}
if (num[i]){
w[++cnt]=w1[i]*num[i];v[cnt]=v1[i]*num[i];
}
}


w,v是新的数组,num[]是每个物品的件数,价值和代价要一起拆。

混合背包

就是把三种背包合起来,读入的时候判断一下件数。(完全背包最多是m/w[i])

然后拆。。。01背包做。

二维费用

数组加一维,循环加一重

像这样(我懒)(下边是个01背包,别的拆一拆。。。)

for (int i=1;i<=n;i++)
for (int j=zl;j>=w[i];j--)
for(int k=tj;k>=v[i];k--)
a[j][k]=max(a[j][k],a[j-w[i]][k-v[i]]+V[i]);


分组背包

for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max(f[v],f[v-c[i]]+w[i])


特别注意一下2、3重循环的顺序。这样才能保证每组内的物品只装一次。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: