算法基础课第五讲 动态规划

算法基础课第五讲 动态规划

时间复杂度:状态数量转移的计算量*

背包问题

  1. 总体概述:给一堆物品,有体积有价值。有一个背包,在背包能装下的前提下最终能装下多少(背包不一定要装满)
  2. DP问题:一般需要从两方面考虑:状态表示以及状态计算
  3. 状态表示:f(i,j) 从两个方面考虑:集合(所有选法的集合)(01背包问题需要满足两个条件:只从前i个物品中选,总体积<=j)和属性(最大值、最小值、数量)
  4. 状态计算:f(N,V) 表示集合的划分(不重不漏)(01背包问题不包含第i个物品、包含第i个物品)
  5. DP问题的优化:对表达式进行转化
    在这里插入图片描述

01背包问题(每个物品只能用一次)

在这里插入图片描述
解题思路:在这里插入图片描述
朴素算法:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];//体积 价值
int f[N][N];
int main()
{
   
	cin >> n >> m;
	for (int i = 1;i <= n;i++)cin >> v[i] >> w[i];
	for(int i=1;i<=n;i++)
		for (int j = 0;j <= m;j++)
		{
   
			f[i][j] = f[i - 1][j];
			if (j >= v[i])f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
		}
	cout << f[n][m] << endl;
	return 0;
}

改善版算法:(使用滚动数组)(循环体积的时候从大到小循环)

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N];
int main()
{
   
	cin >> n >> m;
	for (int i = 1;i <= n;i++)cin >> v[i] >> w[i];
	for (int i = 1;i <= n;i++)
		for (int j = m;j >= v[i];j--)
			f[j] = max(f[j], f[j - v[i]] + w[i]);
	cout << f[m] << endl;
	return 0;
}

完全背包问题(每件物品有无限个)

在这里插入图片描述

思路:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
完全背包问题的状态转移方程:**f[i][j]=f[i-1,j-v[i]k]+w[i]k
朴素算法

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
int main()
{
   
	cin >> n >> m;
	for (int i = 1;i <= n;i++)cin >> v[i] >> w[i];//读入数据
	for (int i = 1;i <= n;i++)
		for (int j = 0;j <= m;j++)//枚举所有状态
			for (int k = 0;k * v[i] <= j;k++)//枚举物品个数
				f[i][j] = max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);
	cout << f[n][m] << endl;

	return 0;
}

改良版:
在这里插入图片描述

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];
int main()
{
   
	cin >> n >> m;
	for (int i = 1;i <= n;i++)cin >> v[i] >> w[i];
	for(int i=1;i<=n;i++)
		for (int j = 0;j <= n;j++)
		{
   
			f[i][j] = f[i - 1][j];
			if (j >= v[i])f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
		}
	cout << f[n][m] << endl;
	return 0;
}

改良版:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N];
int f[N];
int main()
{
   
	cin >> n >> m;
	for (int i = 1;i <= n;i++)cin >> v[i] >> w[i]
  • 53
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值