01背包问题--记忆化搜索and动态规划

继上一篇代码的优化:https://blog.csdn.net/weixin_41676901/article/details/80638440

分析:

暴力搜索的代码可知,反复调用时有些同一参数调用了几次白白浪费了计算时间。

我们可以利用记忆化数组,把已经计算过的参数的结果记录下来,下次需要用时可以直接返回结果。参数的组合为nw种,而函数内只调用2次递归,所以时间复杂度为O(nm),比起O(2^n)效率大幅度提高。

输入样例:

4 5

2 1 3 2

3 2 4 2

输出样例:

7

代码:

扫描二维码关注公众号,回复: 2852918 查看本文章
#include<iostream>
#include<string.h>
using namespace std;
const int N = 100;
int n, w;
int W[N], V[N], dp[N][N];
int max(int a, int b)
{
	return a > b ? a : b;
}
int solve(int i, int j)
{
	int res;
	if (dp[i][j] >= 0)
		return dp[i][j];//直接返回已经计算过的结果
	if (i == n)
		res= 0;
	else if (j < W[i])
		res = solve(i + 1, j);
	else
	{
		res = max(solve(i + 1, j), solve(i + 1, j - W[i]) + V[i]);
	}
	return dp[i][j] = res;//将结果记录在数组中
}
int main()
{
	cin >> n >> w;
	for (int i = 0; i < n; i++)
		cin >> W[i];
	for (int i = 0; i < n; i++)
		cin >> V[i];
	memset(dp, -1, sizeof(dp));//初始化化数组
	cout << solve(0, w);
	return 0;
}

不喜欢用递归的朋友也可以用动态规划,不用写递归函数,简单的二重循环就可以解决这问题。

通过记忆化搜索推导出递推式,待DP熟练后也可以直接得出递推式。

时间复杂度与递归式的记忆化搜索一样是O(nw),但代码简洁了很多

递归式:

①dp[n][j]=0;

②当j<W[i]时:

dp[i][j]=dp[i+1][j];

③其他:

dp[i][j]=max(dp[i+1][j],dp[i+1]]j-W[i]]+V[i])

代码:

#include<iostream>
using namespace std;
const int N = 100;
int n, w;
int W[N], V[N];
int max(int a, int b)
{
	return a > b ? a : b;
}
int main()
{
	int dp[N][N];
	memset(dp, 0, sizeof(dp));
	cin >> n >> w;
	for (int i = 0; i < n; i++)
		cin >> W[i];
	for (int i = 0; i < n; i++)
		cin >> V[i];
	//dp
	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] << endl;
	return 0;
}


猜你喜欢

转载自blog.csdn.net/weixin_41676901/article/details/80638605