#include <iostream> #include <algorithm> using namespace std; /******************************** 01背包 */ #define N 5 #define M 12 int value[N + 1] = { 0, 6, 3, 5, 4, 6 }; int weight[N + 1] = { 0, 2, 2, 6, 5, 4 }; //#define N 5 //#define M 8 //int value[N + 1] = { 0, 1, 2, 3, 10, 1 }; //int weight[N + 1] = { 0, 1, 2, 3, 7, 1 }; int dp[N + 1][M + 1] = { 0 }; //dp[i][j],前i个物品,容量为j的背包,达到的最大价值 int dp1[M + 1] = { 0 }; //将二维空间压缩到一维dp[j],对i迭代,前i个物品,容量为j的背包,达到的最大价值 int path[N + 1][M + 1] = { 0 }; //打印最佳方案的内容使用,path[i][j]表示 //前i个物品,容量为j的背包,达到最佳方案时,第i个物品是否加入了背包。0/1 int main() { for( int i = 0; i <= N; i++ ) { dp[i][0] = 0; } for( int j = 0; j <= M; j++ ) { dp[0][j] = 0; } //dp[i][j],前i个物品,容量为j的背包,达到的最大价值 for( int i = 1; i <= N; i++ ) { for( int j = 1; j <= M; j++ ) { if( weight[i] > j ) { dp[i][j] = dp[i-1][j]; continue; } dp[i][j] = max( dp[i-1][j], dp[i-1][ j-weight[i] ] + value[i] ); } } /******************************** 01背包 输出选择 */ cout << dp[N][M] << endl; cout << "We selected: "; int i = N, j = M; while( i > 0 && j > 0 ) { if( dp[i][j] > dp[i-1][j] ) //说明选择了第i个物品 { cout << i << " "; j -= weight[i];//更改背包的容量j } i--; } for( int j = 0; j <= M; j++ ) { dp1[j] = 0; } //将二维空间压缩到一维dp[j],对i迭代,第i个物品,容量为j的背包,达到的最大价值 //在第i轮(考虑第i个物品是否入到容量为j的背包里)的最大价值,会用到第i-1轮 //(考虑第i-1个物品是否放到容量小于或等于j的背包里)的最大价值。 //因此j的循环要从大到小,这样才保证在第i轮计算dp[j]使用的是第i-1轮的dp[J](J<=j)。 ///在对i的一次迭代中,如当i=1时,把前i个物品放入容量为j的背包里的最大价值,不依赖于把前i个物品放入容量 ///小于j的背包里的最大价值,即相同的i时,第i轮dp[j]的计算不依赖第i轮的dp[J],(J<j)。 for( int i = 1; i <= N; i++ ) { for( int j = M; j >= 1; j-- ) { if( weight[i] > j ) { //dp1[j] = i-1轮的dp1[j],即不变;这个if判断保证了下面的j-weight[i]不会越界。 continue; } if( dp1[j] < dp1[ j-weight[i] ] + value[i] ) { path[i][j] = 1;//物品i加入了背包 } dp1[j] = max( dp1[j], dp1[ j-weight[i] ] + value[i] ); } } /******************************** 01背包 输出选择 */ cout << endl << dp1[M] << endl; cout << "We selected: "; i = N; j = M; while( i > 0 && j > 0 ) { if( path[i][j] == 1 ) //说明选择了第i个物品 { cout << i << " "; j -= weight[i];//更改背包的容量j } i--; } return 0; }
两维背包:
问题描述:1. n个0,m个1
2. 若干种物品,分别由0和1组成,这些物品是:1, 00, 100
3. 最多组成多少种物品。
-------------两维背包,第一维是0的容量为n,第二维是1的容量为m,dp[i][k][j]表示在第一个背包容量为k,第二个背包容量为j的时候,取前i个物品达到的最高价值。这里的价值就是物品的个数。dp[i][k][j]可以压缩到两维dp[k][j]。
#include <iostream> #include <string> #include <vector> using namespace std; vector< string > item; //没有用到 int weight0[21] = { 0 }; int weight1[21] = { 0 }; int dp[501][501] = { 0 }; int main() { int n, m, x; cin >> x >> n >> m; item.push_back(""); string s; for( int i = 0; i < x; i++ ) { cin >> s; item.push_back( s ); int cnt = 0; for( int ind = 0; ind < s.length(); ind++ ) { if( s[ind] == '0' ) { cnt++; } } weight0[i+1] = cnt; weight1[i+1] = s.length() - cnt; //cout << "i: " << i+1 << " " << weight0[i+1] << " " <<weight1[i+1] << endl; } for( int i = 1; i <= x; i++ ) { for( int k = n; k > 0; k-- ) { for( int j = m; j > 0; j-- ) { if( weight0[i] > k || weight1[i] > j ) { continue; } dp[k][j] = max( dp[k][j], dp[ k-weight0[i] ][ j-weight1[i] ] + 1 ); } } } cout << dp[n][m] << endl; return 0; }