dp中的简化背包问题

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

dp1.cpp

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

 
/*简化背包问题
有n个重量和价值分别为Wi,Vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有
挑选方案中价值总和的最大值
1<=n<=100
1<=Wi,Vi<=100
1<=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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值