简单总结一下今天学的背包的相关知识,多有不足之处,还望谅解!!!
背包问题:
-
部分背包问题
-
0 1 背包问题
-
完全背包问题
-
多重背包问题
1.部分背包问题(可以只取物品的一部分放入背包)
采用直观的贪心策略:优先放入''价量比''(价值除以质量)最大的,直到背包不能再放入(或物品已取完)。
2. 0 1 背包问题(每个物品只有两种情况 “放” 或 “不放” )
如果 j < w[ i ] , 则 dp[ i + 1 ][ j ] = dp[ i ][ j ];否则 dp[ i + 1 ][ j ] = max ( dp[ i ][ j ], dp [i ][ j - w[ i ]] + v[ i ])
方法1:(二维数组)
int dp[MAXN][MAXN];
for(int i=0; i<n; i++)
for(int j=0; j<=W; j++)
if(j<w[i])
dp[i+1][j]=dp[i][j];
else
dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
printf("%d\n",dp[n][W]);
方法2:(一维数组)
int dp[MAXN];
for(int i=0; i<n; i++)
for(int j=W; j>=w[i]; j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);
3.完全背包问题(同一物品有无穷件)
状态转移方程
dp[ 0 ][ j ] = 0 ;
dp[ i + 1 ][ j ] = max (dp[i][j - k * w[ i ] ] + k * v[ i ] ) (0 <= k * w[ i ] <= j )
按照上述关系可以写出以下代码:(但是这个代码时间复杂度太高了O(n^3))
for(int i=0; i<n; i++)
for(int j=0; j<=W; j++)
for(int k=0; k*w[i]<=j; k++)
dp[i+1][j]=max(dp[i+1][j],dp[i][j-k*w[i]]+k*v[i]);
printf("%d\n",dp[n][W]);
化简状态方程:
化简后代码:(复杂度O(nW))
方法一:(二维数组)
for(int i=0; i<n; i++)
for(int j=0; j<=W; j++)
if(j<w[i])
dp[i+1][j]=dp[i][j];
else
dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i]);
printf("%d\n",dp[n][W]);
方法二:(一维数组)
int dp[MAXN];
for(int i=0; i<n; i++)
for(int j=w[i]; j<=W; j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);
4. 多重背包(同一物品有多件)
状态转移方程
dp[ i ][ j ] = 到第i 个物品为止总重量不超过j 的所有选法中最有可能的最大值
dp[ i + 1 ][ j ] = max ( dp[ i ][ j ] - k * w[ i ] ] + k * v[ i ] ) (0 <= k <= m[ i ])
方法一:(复杂度为O(V Σ Mi ) )
for(int i=0; i<n; i++)
{
int num=m[i];// 用来找a
for(int k=1; num >0; k< <=1)
{
int mul=min(k,num);
for(int j=W; j>=w[i]*mul; j--)
{
dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul);
}
num -=mul;
}
}
printf("%d\n",dp[W]);
方法二:O(n * m * w)
for(int i = 0; i < n; i++)//n是物品的种类
{
for(int k =1; k < m[i]; k++)//m[i]记录的是第i个物品的数量
{
for(int j = W; j >= w[i]; j--)//w[i]记录的是第i个物品的重量 W是背包的总容量
{
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);//v[i]记录的是第i个物品的价值
}
}
}
背包问题:
-
部分背包问题 贪心
-
0 1 背包问题 ( dp[ j ] = max(dp[ j ], dp[ j - w[ i ]] + v[ i ]) ) (j --) 路径记录
-
完全背包问题 ( dp[ j ] = max(dp[ j ], dp[ j - w[ i ]] + v[ i ]) ) (j ++)
-
多重背包问题 ( dp[ j ] = max(dp[ j], dp[ j - w[ i ]] + v[ i ]) ) 二进制拆分、可行性
C/C++,用 INF = 0x3f3f3f3f表示无穷大,MINN = 0xc0c0c0c0表示无穷小
如有错误请及时提醒博主更正,(@^ --- ^ @)!!!!!!