0-1背包的维度拓展

来源:互联网 发布:小说阅读软件下载 编辑:程序博客网 时间:2024/05/16 00:29

引言
0-1背包是经典的动态规划背包问题之一,也是多数背包问题的基础。0-1背包标准版本(完全表达)需要两个维度,一个表示物品i,一个表示代价j。优化后,可省去物品维度。那么,如果有两种代价又该如何呢?于是,我们将0-1背包拓展一个维度来进行讨论。

核心讲解
取材于现实生活中,你要寄快递,快递对体积和重量均有限制。再比如,常见的军火运输问题,等等。

从背包问题的原理来看,我们只需开两个代价维度就可以了。此时,状态就可以表示为:
dp[i][j][l]
其中,i是物品维度,j是代价A维度,l是代价B维度.
由此可得状态转移方程:

F[i][j][k] = max {    F[i-1][j-v[i]][k-g[i]] + T [i] , (放入第I件物品)     F[i-1][j][k](不放人第 I 件物品)};

参考0-1背包的优化方法,我们可以进行优化:因为所有在表达式中用到的物品维度都是i-1,所以可以采用改正序遍历为倒序遍历,并去除物品维度。
需要注意的是,多维0-1背包问题中不同的代价千万要看清楚,不能混淆。
另则,某些“代价”很灵活,例如对物品数量的限制、购物时间花费等。

典型例题:
【EG】 军火运输
A地到B地需要运输一批军火。已知火车容积、净载重、每个军火的价值、体积和质量。求最大价值的运法。
【输入数据】
Ln1: C和G表示最大运载的体积和重量。
Ln2: N表示有N件。
Ln3~n+2: 每行3个数Ti Vi Gi表示各军火的价值、体积和重量。
【输出数据】
输出可能获得的最大价值。
【样例输入】
6 5 4
10 2 2
20 3 2
40 4 3
30 3 3
【样例输出】
50
【参考程序】

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#define readi(x) scanf("%d",&x)using namespace std;int main(){    freopen("transport.in","r",stdin);    freopen("transport.out","w",stdout);    int ww,cc,i,j,l,dp[405][405],t,c,w,n;    readi(cc);readi(ww);readi(n);    memset(dp,0,sizeof(dp));    for(i=1;i<=n;i++)    {        readi(t);readi(c);readi(w);        for(j=ww;j>=w;--j)            for(l=cc;l>=c;--l)                dp[j][l]=max(dp[j][l],dp[j-w][l-c]+t);    }    cout<<dp[ww][cc]<<endl;    return 0;} 

问题拓展

  1. 【BASED ON EG】如果要对军火的数量进行限制,比如最多只能有N个军火被运输,如何处理?

  2. 【BASED ON EG】如果既要对军火的数量进行限制,比如最多只能有N个军火被运输;同时,这些军火中有部分武器可以无限携带,有部分武器可以最多携带一定数量个;并且,有的武器至少要携带一定数量件;某些武器携带时必须配上一定的弹药才有一定的价值,且在一定范围内弹药越多价值越大。这个问题又该如何处理?

  3. 购物节某人要去各类商店购物。他有N个要买物品,这些物品能够被在指定商店中的若干个内买到,但是花费的时间不同,价格也不同,但对他而言价值是一样的。如何在规定时间内买到最高价值的商品?

0 0
原创粉丝点击