dp中的简化背包问题

来源:互联网 发布:java park 编辑:程序博客网 时间:2024/05/14 04:15

声明:来自《挑战程序设计竞赛》,经过思考总结。

dp1.cpp

内含问题介绍,解决思路,与源代码

/*简化背包问题有n个重量和价值分别为Wi,Vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值1<=n<=1001<=Wi,Vi<=1001<=W<=10000*///以下为基本的穷竭搜索,考虑所有情况#include<iostream>using namespace std;#include<algorithm>//输入int n, W;int w[1000], v[1000];//从第i个物品开始挑选总重小于j的部分,使用时i为0,深层递归至解决问题int rec(int i, int j){int res;//已挑选价值if (i == n )//最后一个物品已挑选完{res = 0;}else if (j < w[i])//j为容许重量{res = rec(i + 1, j);}else{//考虑两种情况,挑选i与不挑选i,然后进入rec(i+1)res = max(rec(i + 1, j), rec(i+1, j - w[i]) + v[i]);}return res;}void Solve(){cout<<rec(0, W);}
dp2.cpp记忆化搜索//在dp1穷竭搜索的基础上进行改进,降低复杂度,使之成为记忆化搜索#include<algorithm>#include<iostream>using namespace std;int n, W;int w[1000], v[1000];int dp[1000][1000];/*记忆化数组,只用于减小复杂度,防止递归浪费,不能取代res,因为还需要用到rec[i+1][j]递归,dp[i+1][j]还未赋值*/int rec(int i, int j){if (dp[i][j] >= 0)//如果计算过dp[i][j],直接返回{return dp[i][j];}int res;if (i == n){dp[i][j] = 0;}else if (j < w[i]){res = rec(i + 1,j);}else{res = max(rec(i + 1,j), rec(i + 1,j - w[i]) + v[i]);}return  dp[i][j]=res;}void solve(){//-1表示尚未计算过,初始化整个数组memset(dp, -1, sizeof(dp));rec(0, W);}dp3.cpp利用递推关系的dp/*1.在dp2中,res与dp[i][j]明显出现了赘余,功能大幅度重叠dp的功能是减小复杂度,局部变量res用于记录已选价值,而dp明显是可以替代res的,只是在dp2的使用过程中,若将未赋值的dp[i+1]赋值给dp[i]将会出错,所以使用rec进行递归而将i从n-1向0开始计算便可以解决这个问题。2.dp数组从全0开始填充,dp[i][j]为根据rec的定义,从第i个物品开始挑选总重小于j的总价值最大值。3.因为没有递归函数的自动运行,加入j循环以下为代码*/#include<algorithm>#include<iostream>using namespace std;int n, W;int w[1000], v[1000];int dp[1000][1000];void solve(){memset(dp, 0, sizeof(dp));//虽然默认初始化为全0,为了可重用性,加入初始化操作for (int i = n - 1; i >= 0; i--){for (int j = 0; j <=W; j++){ if (j < w[i]){dp[i][j] = dp[i + 1][ j];}else{dp[i][j] = max(dp[i + 1][ j], dp[i + 1][ j - w[i]] + v[i]);}}}cout << dp[0][W];}


                                             
1 0