常见背包问题合集

xiaoxiao2021-02-28  63

01背包: 

有nPack件物品和一个容量为nMaxVolume的背包。(每件物品只有一件)第i件物品的费用是c[i],价值是v[i],求解将哪些物品装入背包使总价值最大。转移方程:f[i][nMaxVolume]=max{f[i-1][nMaxVolume],f[i-1][nMaxVolume-c[i]]+v[i]},可以优化只用一维数组.

代码如下:

    int [] record=new int[nMaxVolume+1]    //record[x] 表示背包容量为x 时的最大价值

for(int i=0;i<nPack;i++)

for(int j=nMaxVolume;j>=c[i];j--) if(record[j-c[i]]+v[i]>record[j])

record[j]=record[j-c[i]]+v[i];

完全背包 

如果物品不计件数,就是每个物品不只一件的话,稍微改下即可  

for(int i=0;i<nPack;i++) for(int j=c[i];j<=nMaxVolume;j++) if(record[j-c[i]]+v[i]>record[j])

record[j]=record[j-c[i]]+v[i];

  record[nMaxVolume] 即为所求          初始化分两种情况:        1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w] = -INF;  

        2、如果不需要正好装满 f[0~v] = 0;  

多重背包:

每个物品给出确定的件数,求可以得到的最大价值。 

for(i=0;i<nPack;i++) for(j=0;j<bag[i];j++) for(k=nManVolume;k>=c [i];k--) if(record[j-c[i]]+v[i]>record[j])

record[j]=record[j-c[i]]+v[i];

优化版本:

//0-1背包,代价为cost,获得的价值为weight void ZeroOnePack(int cost,int weight) { for( int i=nValue;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } //完全背包,代价为cost,获得的价值为weight void CompletePack(int cost,int weight) { for( int i=cost;i<=nValue;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } //多重背包 void MultiplePack(int cost,int weight,int amount) { if(cost*amount>=nValue) CompletePack(cost,weight); else { int k= 1; while(k<amount) { ZeroOnePack(k*cost,k*weight); amount-=k; k<<= 1; } ZeroOnePack(amount*cost,amount*weight); } }

 

混合背包

01背包,完全背包,多重背包的混合体

for(i= 0;i<n;i++) { if(第i件物品是 01背包) ZeroOnePack(c[i],v[i]); else if(第i件物品是完全背包) CompletePack(c[i],v[i]); else if(第i件物品是多重背包) MultiplePack(c[i],v[i]); }

二维背包:

对于每件物品有两种不同费用,比如有n种物品,每种物品都有体积vi,重量wi,价值ti,限制体积最多为V,重量最多为W

增加了一维费用,只需要状态也增加一维即可。设f[i][x][y]表示前i件物品,付出两种代价分别为x和y时可以获得的最大价值。

f[i][x][y]=max{f[i-1][x][y],f[i-1][x-v[i]][y-w[i]]+t[i]} 

for(i= 0;i<n;i++) { for( int x=V;x>=v[i];x--) { for( int y=W;y>=w[i];y--) { f[x][y]=max(f[x-v[i]][y-w[i]]+t[i],f[x][y]); } } }

分组背包:有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

for( int i= 1;i<=n;i++) //有n组 for( int j=V;j>= 1;j--) //从后往前遍历 for( int k= 1;k<=m;k++) //第i组内的各个数据 if(j-k>= 0&&dp[j]<dp[j-cost[i][k]]+value[i][k])dp[j]=dp[j-cost[i][k]]+value[i][k]; //cost[i][j]表示第i组第j个物品的花费,value[i][j]表示第i组第j个物品的价值

需要注意的细节:

如果没有要求背包一定要装满,则record[i]初始化为0。如果要求一定要装满,则除了record[0]为0之外其他record[i]初始化为-INF。

转载请注明原文地址: https://www.6miu.com/read-2619901.html

最新回复(0)