AcWing 1017. 怪盗基德的滑翔翼(线性dp 最长上升子序列模型)

怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。

而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。

不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有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

题目描述

题目给定一个长度为 n 的一维数组 w[n],表示每个楼房的高度

怪盗基德可以选定任意一个楼房,作为他的起始位置

他可以选择向左或向右出发直到边界,途中不能改变方向

题目要求我们找出一条路径,使得他飞行的路线上,经过的高度递减的楼房子序列长度最大

输出该子序列的长度。

思路

相比于AcWing 895 最长上升子序列 :

  • 怪盗基德的起点任意

  • 方向任意, 不过一旦确定方向就不能回头了

假设已经确定 起点方向第i个楼向左滑行, 实际上我们求的是 : 以ai作为起点的
最长下降子序列(向左) 等价于 以a[i]为终点的最长上升在子序列(向右).

回忆在LIS问题求解中, 我们从左向右计算每次以i为终点, 也就是计算了所有元素作为终点的情况. 所以
本题和最长上升子序列问题唯一的不同在于需要计算2个方向。

微信图片_20220112181619.png

微信图片_20220112181753.png

状态表示dp[i]

集合:以第i个位置作为右端点的所有严格递增子序列

属性:子序列长度的最大值Max

具体过程参考:最长上升子序列

微信图片_20220112182748.png

#include<bits/stdc++.h>

using namespace std;

int k;
int n;
const int N = 110;
int h[N];
int dp[N];

int main()
{
	cin>>k;
	while(k--)
	{
		cin>>n;
		for(int i=1;i<=n;++i) cin>>h[i];
		
		int res = -1;
		//基德往左边跳,相当于从左向右正向求LIS问题
		for(int i=1;i<=n;++i)
		{
			dp[i]=1;
			for(int j=1;j<i;++j)
			{
				if(h[j]<h[i])
				{
					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(h[j]<h[i])
				{
					dp[i]=max(dp[i],dp[j]+1);
				}
			}
			res = max(res,dp[i]);
		}
		
		cout<<res<<endl;
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值