宣传一下算法提高课整理 <—
本题链接(AcWing)
https://www.acwing.com/problem/content/description/1012/
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。
由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
共一行,输入导弹依次飞来的高度。
输出格式
第一行包含一个整数,表示最多能拦截的导弹数。
第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。
数据范围
雷达给出的高度数据是不大于 30000 的正整数,导弹数不超过 1000。
样例输入
389 207 155 300 299 170 158 65
样例输出
6
2
思路
(转载自AcWing@空空如也)
1、首先我们把这些导弹分为s组(s即为所求答案)
可以看出每一组都是一个不升子序列
2、划分完后我们在组一里找一个原序列里以组一的开头点连续的不升子串的最后一个元素,可以知道在组2中一定有一个大与它的点
(如果组二中没有的话,那么组二中最高的导弹高度必然小于这个点,而其他的高度都小于这个高度而且是递减或相等的,那么没有必要再开一个组二了,矛盾,所以不存在找不到比他大的点的情况)
3、以此类推,对于每一个k组(1<=k<n)都可以找到这样的一些点
所以把这些点连起来,就是一条上升子序列。
4、设最长上升子序列长度为l
所求上升子序列为h
那么h<=l
因为最长上升子序列任意两个不在一组内
(如果在同一个组内,则每个组的数不成为一个不生子序列,矛盾)
所以l==h比较难理解
我们来看组数据
389 207 155 300 299 170 158 65
组一 389 207 155 65 组二 300 299 170 158
步骤一中我们一开始找到的点是1
组二里可以找到300比他大
所以最长上升子序列长度为2 == 答案
(以下是作者写的)
那么我们可以把这个问题转化为两部DP问题,即“最长不上升子序列”与“最长上升子序列”问题
由于数据范围是1000,因此朴素的LIS做法($O(n^2)$)是可以AC的
$AC$ $Code$:
$C++$
#include <iostream>
using namespace std;
const int N = 1010;
int n;
int a[N];
int f[N], g[N];
int r1, r2;
int main()
{
while (cin >> a[n]) n ++ ;
for (int i = 0; i < n; i ++ )
{
f[i] = g[i] = 1;
for (int j = 0; j < i; j ++ )
if (a[j] >= a[i]) f[i] = max(f[i], f[j] + 1);
else g[i] = max(g[i], g[j] + 1);
}
for (int i = 0; i < n; i ++ )
{
r1 = max(r1, f[i]);
r2 = max(r2, g[i]);
}
printf("%d\n%d\n", r1, r2);
return 0;
}
最后,如果觉得对您有帮助的话,点个赞再走吧!