题目描述
计算最少出列多少位同学,使得剩下的同学排成合唱队形
说明:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<=K)使得T1<T2<......<Ti-1<Ti>Ti+1>......>TK。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入描述:
整数N
输出描述:
最少需要几位同学出列
输入例子:
8 186 186 150 200 160 130 197 200
输出例子:
4
解题思路
动态规划法,最长子序列问题
题目意思就是将输入的数组元素组成先递增、后递减的模式,求最少要排除多少个无序的项。也就转化成“求子队伍最大人数”的问题。
遍历每个位置一遍求出左、右两侧可排人数难以实现,故采用动态规划思想:
先从左往右规划一遍,记录各位置左侧队伍人数;再从右往左规划一遍,记录各位置右侧队伍人数,然后相加即可得出各位置对应的子队伍人数,从而求出能排出的最大队伍人数。
AC代码如下:
#include <iostream>
#include <stdio.h>
using namespace std;
struct person{
int height;
int num_l;
int num_r;
}a[1000000];
int main()
{
int n;
while( scanf("%d",&n)!=EOF ){
for( int i=0;i<n;++i ){
scanf("%d", &a[i].height );
a[i].num_l = 0;
a[i].num_r = 0;
}
/*从左到右dp一遍*/
for( int i=1;i<n;++i ){
for( int j=i-1;j>=0;--j ){
if( a[i].height>a[j].height && a[i].num_l<a[j].num_l+1 ){
a[i].num_l = a[j].num_l + 1;
}
}
}
/*从右到左dp一遍*/
for( int i=n-2;i>=0;--i ){
for( int j=i+1;j<n;++j ){
if( a[i].height>a[j].height && a[i].num_r<a[j].num_r+1 ){
a[i].num_r = a[j].num_r + 1;
}
}
}
/*组合两边dp结果,算出队伍最大人数*/
int maxNum = 0;
for( int i=0;i<n;++i ){
if( a[i].num_l+a[i].num_r+1 > maxNum ){
maxNum = a[i].num_l+a[i].num_r+1;//左边人数+右边人数+本身
}
}
/*总人数减去队伍人数最大值即为出列人数的最小值*/
printf("%d\n", n-maxNum );
}
return 0;
}