AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细)

这篇具有很好参考价值的文章主要介绍了AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

(1)acwing 4557. 最长上升子序列 4557. 最长上升子序列 - AcWing题库

给定一个长度为 N 的整数序列 a1,a2,…,aN。请你计算该序列的最长上升子序列的长度。上升子序列是指数值严格单调递增的子序列

输入格式
  • 第一行包含整数 N
  • 第二行包含 N个整数 a1,a2,…,aN
输出格式
  • 一行,一个整数,表示最长上升子序列的长度
数据范围
  • 1≤N≤1000
  • 0≤ai≤100000
输入样例:
7
1 7 3 5 9 4 8
输出样例:
4

 C++代码:

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1010;

int n,res=0;
int arr[N],dp[N];

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
    for(int i=1;i<=n;i++) {
        dp[i]=1;
        for(int j=1;j<i;j++) {
            if(arr[j]<arr[i]) 
                dp[i] = max(dp[i],dp[j]+1);
        }
        if (res < dp[i]) res = dp[i]; // 取长的子序列
    }
    printf("%d\n",res);
    return 0;
}

也可以这样写:

int main() {
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&arr[i]);
    dp[0]=1;
    for(int i=1;i<n;i++) {
        dp[i]=1;
        for(int j=0;j<i;j++) {
            if(arr[j]<arr[i]) 
                dp[i] = max(dp[i],dp[j]+1);
        }
        if (res < dp[i]) res = dp[i]; // 取长的子序列
    }
    printf("%d\n",res);
    return 0;
}

======================================================

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
    dp[1]=1;
    for(int i=2;i<=n;i++) {
        dp[i]=1;
        for(int j=1;j<i;j++) {
            if(arr[j]<arr[i]) 
                dp[i] = max(dp[i],dp[j]+1);
        }
        if (res < dp[i]) res = dp[i]; // 取长的子序列
    }
    printf("%d\n",res);
    return 0;
}

(2)acwing1017-怪盗基德的滑翔翼

假设城市中一共有 N幢 建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)

输入格式

  • 输入数据第一行是一个整数K,代表有K组测试数据
  • 每组测试数据包含两行:第一行是一个整数N,代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h,按照建筑的排列顺序给出

输出格式

  • 对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量

数据范围

  • 1≤K≤100,
  • 1≤N≤100,
  • 0<h<10000

输入样例:

3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10

输出样例:

6
6
9

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

思路:移动方向一旦确定,就转换成了LIS问题,那么可以看作是两个方向的最长上升子序列问题,答案res为正向逆向LIS两个过程中的较大者

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解 C++代码:

// 当确定完方向和起点后,最长的距离是什么呢?
// 起点:a[i]
// 最长距离:以a[i]为结尾的最长上升子序列

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n;
int arr[N],dp[N];

int main() {
	int T;
	scanf_s("%d", &T);
	while (T--) {
		scanf_s("%d", &n);
		for (int i = 1; i <= n; i++) scanf_s("%d", &arr[i]);
		// 正向求解LIS问题
		int res = 0;
		for (int i = 1; i <= n; i++) {
			dp[i] = 1;
			for (int j = 1; j < i; j++) {
				if (arr[i] > arr[j]) dp[i] = max(dp[i], dp[j] + 1);
			}
			res = max(res, dp[i]);
		}
		// 反向求解LIS问题
		for (int i = n; i>=1; i--) {
			dp[i] = 1;
			for (int j = n; j > i; j--) {
				if (arr[i] > arr[j]) dp[i] = max(dp[i], dp[j] + 1);
			}
			res = max(res, dp[i]);
		}
		printf("%d\n", res);
	}
	return 0;
}

(3)acwing1014-登山问题

五一到了,ACM队 组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个浏览景点的编号。同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?

输入格式

  • 第一行包含整数N,表示景点数量
  • 第二行包含N个整数,表示每个景点的海拔

输出格式

  • 输出一个整数,表示最多能浏览的景点数

数据范围

  • 2≤N≤1000

输入样例

8
186 186 150 200 160 130 197 220

输出样例

4

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

本题实质上是求正向反向两次LIS问题,两次的LIS过程相互独立,故所求为两端LIS过程中最长上升子序列的最大长度之和

  • res = max(res,f[i]+g[i]-1)

C++代码:

/*
	条件1:按照编号递增的顺序来浏览 => 必须是子序列
	条件2:相邻两个景点不能相同
	条件3:一旦开始下降,就不能上升了

	目标:求最多能浏览多少景点
*/

#include <iostream>
#include <algorithm>

using namespace std;
const int N = 1010;

int n;
int arr[N];
int f[N], g[N];

int main() {
	scanf_s("%d", &n);
	for (int i = 1; i <= n; i++) scanf_s("%d", &arr[i]);
	for (int i = 1; i <= n; i++) {
		f[i] = 1;
		for (int j = 1; j < i; j++) {
			if (arr[i] > arr[j]) f[i] = max(f[i], f[j] + 1);
		}
	}
	for (int i = n; i >= 1; i--) {
		g[i] = 1;
		for (int j = n; j > i; j--) {
			if (arr[i] > arr[j]) g[i] = max(g[i], g[j] + 1);
		}
	}
	int res = 0;
	for (int i = 1; i <= n; i++) res = max(res, f[i] + g[i] - 1);
	printf("%d\n", res);
	return 0;
}

(4)acwing 482.合唱队形 482. 合唱队形 - AcWing题库

N 位同学站成一排,音乐老师要请其中的 (N−K) 位同学出列,使得剩下的 K 位同学排成合唱队形。合唱队形是指这样的一种队形:设 K 位同学从左到右依次编号为 1,2…,K 他们的身高分别为 T1,T2,…,TK 则他们的身高满足 T1<…<Ti>Ti+1>…>TK(1≤i≤K)。你的任务是,已知所有 N 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入格式
  • 输入的第一行是一个整数 N ,表示同学的总数
  • 第二行有 N 个整数,用空格分隔,第 i  个整数 Ti  是第 i 位同学的身高(厘米)
输出格式
  • 输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列
数据范围
  • 2≤N≤100
  • 130≤T≤230

思路: 如果要使得出列的同学数量最少的话,就意味着要使剩下的数量最多。那意思就是要找到一个先上升再下降的序列,选个最大的。然后再用总数减去这个长度。

#include <iostream>
#include <algorithm>

using namespace std;
const int N = 1010;

int n;
int arr[N];
int f[N],g[N];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &arr[i]);
    for(int i=1;i<=n;i++) {
        f[i] = 1;
        for(int j=1;j<i;j++) {
            if(arr[i]>arr[j]) f[i] = max(f[i], f[j] + 1);
        }
    }
    for(int i=n;i>=1;i--) {
        g[i] = 1;
        for(int j=n;j>i;j--) {
            if(arr[i]>arr[j]) g[i] = max(g[i], g[j] + 1);
        }
    }
    int res=0;
    for(int i=1;i<=n;i++) res = max(res,f[i]+g[i]-1);
    printf("%d",n-res);
    return 0;
}

(5)acwing 1012.友好城市

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

输入样例: 

7
22 4
2 6
10 3
15 12
9 8
17 17
4 2

输出样例: 

4

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

 AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

>>思路和分析

对于任意一种合法的建立桥梁的方式,都可以对应一种因变量的上升子序列。反之,对于因变量的任何一个上升子序列,我们都可以唯一的对应一个合法的建桥方式。每一种建桥方式,建桥的数量和上升子序列的长度是相同的。因此左边集合(所有合法的建桥方式)的长度最大值就等于右边集合(上升子序列)的长度的最大值。
解法:先按照自变量的大小,把因变量排序。排好之后得到一个序列,然后在序列当中求最长的一个上升子序列。
排序思路:看一下什么会出现相交的情况?
本质:如果选出来的桥梁是没有交叉的,那么就意味着按照其中某一个点来排序,那么另外一个点对应的位置也一定要使有序的才可以。因为一旦出现逆序,就是有交叉的。没有交叉也就意味着一定没有逆序的。那本题其实就可以转化为求最长上升子序列的长度。 

C++代码: 

#include <iostream>
#include <algorithm>

using namespace std;

typedef pair<int, int> PII;

const int N = 5010;

int n;
PII q[N];
int f[N];

int main() {
	scanf_s("%d", &n);
	for (int i = 0; i < n; i++) scanf_s("%d%d", &q[i].first, &q[i].second);
	sort(q, q + n);

	int res = 0;
	for (int i = 0; i < n; i++) {
		f[i] = 1;
		for (int j = 0; j < i; j++) {
			if (q[i].second > q[j].second) f[i] = max(f[i], f[j] + 1);
		}
		res = max(res, f[i]);
	}
	printf("%d\n",res);
	return 0;
}

(6)acwing 1016.最长上升子序列和

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解

输入样例:  

7
1 7 3 5 9 4 8

 输出样例: 

18

AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细),最长上升子序列模型,动态规划,图解 C++代码:文章来源地址https://www.toymoban.com/news/detail-736552.html

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;
int n;
int a[N], f[N];

int main() {
	scanf_s("%d", &n);
	for (int i = 1; i <= n; i++) scanf_s("%d", &a[i]);
	for (int i = 1; i <= n; i++) {
		f[i] = a[i];
		for (int j = 1; j <i; j++) {
			if (a[i] > a[j]) f[i] = max(f[i], f[j] + a[i]);
		}
	}
	int res = 0;
	for (int i = 1; i <= n; i++) res = max(res, f[i]);
	printf("%d\n", res);
	return 0;
}

到了这里,关于AcWing 1.2.1 最长上升子序列模型 + 动态规划 + 图解(详细)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划__最长上升子序列

    目录 一.最长上升子序列 最长上升子序列模板 O(n ^ 2) 最长上升子序列二分优化 O(nlongn) 1017. 怪盗基德的滑翔翼 1014. 登山 1012. 友好城市 1016. 最大上升子序列和 1010. 拦截导弹 187. 导弹防御系统 二.最长公共上升子序列 最长公共子序列 最长公共上升子序列 给定一个长度为 N 的数

    2024年02月04日
    浏览(41)
  • C++动态规划之最长上升子序列

    一个序列A={a1,a2,...an}中任意删除若干项,剩余的序列叫做A的一个子序列。例如序列A={1,3,5,4,2},删除其中的第3项和第5项,得到序列B={1,3,4},删除其中的第3项和第4项,得到序列C={1,3,2},此时序列B和C是序列A的子序列。 如果序列中的元素是从小到大排列的,则该序列为上升

    2023年04月14日
    浏览(43)
  • (Java) 算法——动态规划 最长公共子序列 图解

    遇到了用动态规划来求解最长公共子序列问题,算法这块儿比较薄弱,便想着在网上找现成的思路和代码,也算拾人牙慧,但有一点没想到,都已经22年了,关于LCS问题网上给出的答案如此一言难尽……,只有零散几篇对于 新手 来说比较友好,但也仅仅这样,好在自己花了点

    2023年04月08日
    浏览(47)
  • 最长上升子序列模型(LIS)

    最长上升子序列模型就像它的名字一样,用来从区间中找出最长上升的子序列。它主要用来处理区间中的挑选问题,可以处理上升序列也可以处理下降序列,原序列本身的顺序并不重要。 895. 最长上升子序列(活动 - AcWing) 896. 最长上升子序列 II(活动 - AcWing) 我们就这两个

    2024年01月19日
    浏览(40)
  • C++---最长上升子序列模型---最大上升子序列和(每日一道算法2023.3.3)

    注意事项: 本题为\\\"线性dp—最长上升子序列的长度\\\"的扩展题,所以dp思路这里就不再赘述。 题目: 比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),(3,4,8)等。 这些子序列中和最大为18,为子序列(1,3,5,9)的和。 你的任务,就是对于给定的序列,求出最大上升子序

    2024年02月03日
    浏览(37)
  • 两个数组的动态规划——最长公共子序列模型

    1.考虑空串,即dp表多出一行一列, 代表某个字符串为空。 2.考虑最后一个位置;是否相等; 3.可在字符串最前面加虚拟位置以对应映射关系; 4.一般横行是j,列是i。此时第一行代表第二个字符串不为空,即第一个字符串是空的 给你两个字符串  s   和  t  ,统计并返回在

    2024年03月10日
    浏览(65)
  • 上升子序列的最大长度,递归-记忆化搜索-动态规划三步走

    题目描述: 小明有一个数组,他想从数组任意元素开始向后遍历,找出所有上升子序列,并计算出最长的上升子序列的长度。 数据范围: 每组数据长度满足 1≤n≤200 1≤n≤200 , 数据大小满足 1≤val≤350 1≤val≤350 输入描述: 数据共2行,第1行先输入数组的个数,第2行再输

    2024年04月22日
    浏览(41)
  • 最长上升子序列问题(LIS问题)与最长不上升子序列问题的四种方法(c++ 模板代码)

    最大上升子序列问题也叫做LIS问题,与最大公共子序列LCS问题是一类经典问题,在本章我们将总结一下求解 LIS最大上升子序列 的 几种方法 ,同时也会给出对应的 最大不上升子序列的求解方法。 关于LCS问题,我在后面会再出一篇博客来讲解, 废话不多说,我们直接进入正题

    2024年02月03日
    浏览(43)
  • 最长公共上升子序列(LCIS)

    目录 一、前言 二、最长公共上升子序列 1、问题描述 2、基本思路 (1)状态表示 (2)状态计算 三、题例 1、上链接 2、基本思路 3、代码 (1)python未优化版 (2)python优化版 对于学计算机的同学来说,学习算法是一件非常重要的事情,废话不多讲,我们来讲讲“最长公共上

    2023年04月09日
    浏览(34)
  • [ACM 学习] 最长上升子序列

    LIS(最长上升子序列)的三种经典求法 - 一只不咕鸟 - 博客园 (cnblogs.com) 理解一下第三种方法(贪心+二分查找) 因为构建的是上升子序列,所以是可以用二分查找找到最大的小于当前 A[i] 的在子序列中的 F[j],并更新 F[j+1] 注:刚开始看的时候还在疑惑只换一个的话,后面的

    2024年01月16日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包