题目描述
位同学站成一排,音乐老师要请其中的 ( N − K ) (N-K) (N−K)位同学出列,使得剩下的 K K K位同学排成合唱队形。
合唱队形是指这样的一种队形:设 K K K位同学从左到右依次编号为 1 , 2 … , K 1,2…,K 1,2…,K,他们的身高分别为 T 1 , T 2 , … , T K T_1,T_2,…,T_K T1,T2,…,TK, 则他们的身高满足 T 1 < … < T i > T i + 1 > … > T K ( 1 ≤ i ≤ K ) T_1<…<T_i>T_{i+1}>…>T_K(1≤i≤K) T1<…<Ti>Ti+1>…>TK(1≤i≤K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
输入的第一行是一个整数
N
N
N,表示同学的总数。
第二行有 n n n个整数,用空格分隔,第 i i i个整数 T i T_i Ti是第i位同学的身高(厘米)。
输出格式
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
数据范围
2
≤
N
≤
100
2≤N≤100
2≤N≤100,
130
≤
T
i
≤
230
130≤T_i≤230
130≤Ti≤230
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4
算法思想(线性DP)
从题目描述来看合唱队形应该是一个“山”字形,中间最高,从左侧到中间是一个严格单调递增序列,从右侧到中间也是一个严格单调递增序列。因此可以利用线性DP的思想:
- 从左到右求一次严格单调递增序列的最大长度
- 从右到左求一次严格单调递增序列的最大长度
- 枚举中间位置,求两边同时为严格单调序列时的最大长度,即为需要留下来的同学人数。
时间复杂度
O ( n 2 ) O(n^2) O(n2)
代码实现
#include <iostream>
using namespace std;
const int N = 110;
int a[N], f1[N], f2[N];
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
//从左向右求严格上升子序列的最大长度
for(int i = 1; i <= n; i ++)
{
int m = 0;
for(int j = 1; j < i; j ++)
if(a[j] < a[i] && f1[j] > m) m = f1[j];
f1[i] = m + 1;
}
//从右向左求严格上升子序列的最大长度
for(int i = n; i >= 1; i --)
{
int m = 0;
for(int j = n; j > i; j --)
if(a[j] < a[i] && f2[j] > m) m = f2[j];
f2[i] = m + 1;
}
int ans = 0;
//枚举中间位置
for(int i = 1; i <= n; i ++)
ans = max(ans, f1[i] + f2[i] - 1);
cout << n - ans << endl;
return 0;
}