合唱队形【NOIP2004提高组第三题】【DP动态规划】

题目链接

题目描述

NN 位同学站成一排,音乐老师要请其中的( N-KN−K )位同学出列,使得剩下的 KK 位同学排成合唱队形。

合唱队形是指这样的一种队形:设K位同学从左到右依次编号为 1,2,…,K1,2,…,K ,他们的身高分别为T1,T2,…,TK , 则他们的身高满足T1<…Ti+1>…>TK(1≤i≤K) 。

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入输出格式

  • 输入格式:

共二行。

第一行是一个整数N(2≤N≤100) ,表示同学的总数。

第二行有 n 个整数,用空格分隔,第 i 个整数 Ti(130≤Ti≤230) 是第 ii 位同学的身高(厘米)。

  • 输出格式:

一个整数,最少需要几位同学出列。

输入输出样例

输入样例#1:

8
186 186 150 200 160 130 197 220

输出样例#1:

4

说明

  1. 对于50%的数据,保证有 n \le 20n≤20 ;
  2. 对于全部的数据,保证有 n \le 100n≤100 。

解题思路

先用最长上升子序列求一遍,存在high数组里,再用最长下降子序列求一遍,存在low数组里。

重点:第x个人为队形中最高者时,队形的最大长度=x及其左侧的最长上升子序列长度+x及其右侧的最长下降子序列长度-1(x被算了两次)。这点理解了,题目就不难了。

注意求的是出列人数,所以最后勿忘用n减。这是我连交三次都20分的原因(ಥ﹏ಥ)

AC code:

#include<bits/stdc++.h>
const int MAXN=101;
using namespace std;
int n;
int a[MAXN];
int high[MAXN],low[MAXN];
int ans=0;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)                       //求整个序列中每个元素及其左侧的
    {                                          //最长上升子序列长度
        high[i]=1;
        for(int j=1;j<i;j++)
            if(a[i]>a[j])
                high[i]=max(high[i],high[j]+1);
    }
    for(int i=n;i>0;i--)                        //求整个序列中每个元素及其右侧的
    {                                          //最长下降子序列长度
        low[i]=1;
        for(int j=n;j>i;j--)
            if(a[i]>a[j])
                low[i]=max(low[i],low[j]+1);
    }
    for(int i=1;i<=n;i++)                       //找到最长队形
        ans=max(ans,high[i]+low[i]-1);
    printf("%d\n",n-ans);                       //用n减!!!
    return 0;
}

猜你喜欢

转载自blog.csdn.net/fail_perfectly/article/details/81541780