您的位置:首页 > 其它

dp中的简化背包问题

2017-02-08 10:22 169 查看
声明:来自《挑战程序设计竞赛》,经过思考总结。

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];
}




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: