同样先给出需要记住的一维代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int v[MAXN]; // 体积
int w[MAXN]; // 价值
int dp[MAXN];
int main()
{
int n, m;//n是个数,m是背包总容量
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];
for(int i = 1; i <= n; i++)
for(int j = v[i]; j <= m; j++){
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
cout << dp[m];
return 0;
}
与一维的01背包代码仅仅只有j循环的顺序不同。
为什么?
同样我们要仿照二维的思路思考。
如果是二维的话推理可得
dp [ i ][ j ] = max( dp[ i - 1][ j ] , dp[ i - 1][ j - v ] + w , dp[ i -1][ j - 2v ] + 2w , dp [ i-1 ][ j - 3v] + 3w , …)
这么多项啊,那岂不是要循环,又多加一维,三维循环?
可是 我们可以思考一下,f[i][j-v]等于多少?
实际上,在完全背包问题里,
dp[ i ][ j - v ] = max(dp[ i - 1 ][ j - v ],dp[ i - 1 ][ j - 2v ]+w,dp[ i -1 ][ j - 3v ]+2w,…)
观察一下两个式子,我们将它们结合一下
dp [ i ][ j ]=max(dp[ i - 1 ][ j ],dp[ i ][ j - v ]+w);
所以完全背包的一维的程序里面的 j 循环是顺序的,
这样 dp [ j - v[ i ]] 就先被更新,就相当于dp[ i ][ j - v[ i ] ]
这里也放上二维的代码供参考
#include <iostream>
using namespace std;
int w[1005],v[1005],dp[1005][1005];
int n,m;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
if(v[i]>j) dp[i][j]=dp[i-1][j];
else dp[i][j] = max(dp[i-1][j], dp[i][j-v[i]]+w[i]);
}
}
cout<<dp[n][m];
}
如果是求物品总体积恰等于背包容量,
要对dp[ i ] 数组初始化
for(int i = 1; i <= m ; i ++) dp [ i ] = - inf ;(求最大值)
for(int i = 1; i <= m ; i ++) dp [ i ] = inf ;(求最小值)
只让 dp [ 0 ] = 0;