注意事项:
本题为"线性dp—最长上升子序列的长度" 和 “最长上升子序列模型—怪盗基德的滑翔翼” 和 “最长上升子序列模型—登山” 的扩展题,所以dp思路这里就不再赘述。
题目:
N位同学站成一排,音乐老师要请其中的
(
N
−
K
)
(N-K)
(N−K) 位同学出列,使得剩下的
K
K
K 位同学排成合唱队形。
你的任务是,已知所有 N 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
输入的第一行是一个整数
N
N
N,表示同学的总数。
第二行有
N
N
N 个整数,用空格分隔,第
i
i
i 个整数
T
i
T_i
Ti 是第
i
i
i 位同学的身高(厘米)。
输出格式
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
数据范围
2
≤
N
≤
100
2 \le N \le 100
2≤N≤100,
130
≤
T
i
≤
230
130 \le T_i \le 230
130≤Ti≤230
输入:
8
186 186 150 200 160 130 197 220
输出:
4
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int w[N], f1[N], f2[N];
int n;
//最长上升子序列模板,(int* f)是引用arr
void lis(int* f)
{
for (int i = 1; i<=n; i++) {
f[i] = 1;
for (int j = 1; j<i; j++) {
if (w[j] < w[i]) f[i] = max(f[i], f[j]+1);
}
}
}
int main ()
{
//接收数据
cin >> n;
for (int i = 1; i<=n; i++) cin >> w[i];
//求两遍,一次最长上升子序列,一次最长下降子序列
lis(f1);
reverse(w+1, w+n+1);
lis(f2);
//把每个峰值点的上升和下降加在一起,算所有点作为峰值的max即可
int res = 0;
for (int i = 1; i<=n; i++) x = max(x, f1[i]+f2[n-i+1]); //这里因为下降子序列是反着求的,所以下标也是需要反着来
cout << n-res+1 << endl; //这里是和“登山”那题的唯一不同点,我们是要取最少需要多少人出列。
return 0;
}
思路:
很简单,前面的 计算/思路 和登山那题完全一样,最后输出的时候只要用 总人数 - 峰值Max + 1 即可计算出需要多少人出列。
究极水题!
声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流