dp入门课(三)

请先阅读dp入门课一二,不然不好看懂。

dp入门课(一)-CSDN博客

dp入门课(二)-CSDN博客

上次的基础例题比较简单,就是已经讲过的背包。

直接给代码吧:

第一题:

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

第二题:

#include <bits/stdc++.h>
using namespace std;
const int N = 21000;
int n, m;
int f[N];
int main() {
	cin >> m >> n;
	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;
}

提高的那道例题,就是咱们几天要讲的内容。

大家先读一遍题:B3637 最长上升子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大家先自己回忆一下上次讲的dp的4个步骤。

如果忘了,我就再列出来一次:

第一步,设置状态

第二步,推状态转移方程

第三步,确定边界

第四步,写代码

 我们先思考几个问题:

问:该题如何设置状态?

答:f[i]表示以第i个数为结尾的答案的最大值。

问:状态如何转移?

答:首先枚举i,然后再枚举一个j,如果第j个数小于第i个数,我们就考虑第i个数接在第j个数后面,并且取个max。

问:这题边界如何处理?

答:这题无边界,但f[i]的初始值应该为1。

问:答案是什么?f[n]吗?

答:不是f[n],是在f数组当中取最大值。

代码如下:

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

大家记住,该模型的名字就叫做最长上升子序列。

布置一道习题,也是下节课的内容:

897. 最长公共子序列 - AcWing题库

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值