dp入门课(一)

今天,我们要讲一个算法,他的名字叫做动态规划,也叫dp。

不知道大家学过贪心算法没有,没学过可以自己查一下。

先看一道例题,了解一下dp:

链接:2. 01背包问题 - AcWing题库

大家先尝试一下贪心算法。

如果你按着 v[i] 的大小来选,我可以举出反例:

3 5

1 2

1 3

5 100000

答案是100000,你的程序对了吗?

如果你按着 w[i] 来选,我也可以举出反例:

3 5

1 10

5 12

3 1

答案是50,你的程序对了吗?

这道题,如果你dfs或bfs,直接超时。

而用贪心,又会错。

于是我们引入新概念:

DP!

我们可以开一个二维数组,就叫做f吧。

f[i][j]代表在前i个中用j元钱能获得的最大价值。

假设我们知道f[i][j]之前的所有数,如何求出f[i][[j]?

我们来看一看。

首先,f[i][j]=f[i-1][j].

有人会问:为什么呢?

大家想想,我这步假设啥也不去,那答案就是f[i-1][j],所以我们可以让他先等于这个值,再枚举每件物品,看选择它或不选择他的答案那个大,就选择那个。

所以代码就是这样:

#include <bits/stdc++.h>
using namespace std;
const int N = 5010;
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 = 1; j <= m; j ++ ){
			
			f[i][j] = f[i - 1][j];
			if (j - v[i] >= 0){
				f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
			}
		}
	}
	cout << f[n][m] << endl;
	return 0;
}

我们在思考一下,是不是i的那一维度完全用不到,我们就可以把i的那一维减下来。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int f[N];
int main(){
	int n,m;
	cin >> n >> m;
	for (int i = 1; i <= n; i ++ ){
		int v,w;
		cin >> v >> w;
		for (int j = m; j >= v; j -- ){
			f[j] = max(f[j],f[j - v] + w);
		}
	}
	cout << f[m];
	return 0;
}

好,今天就讲到这里,给大家布置一个习题:3. 完全背包问题 - AcWing题库

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值