合唱队形

 

题目描述

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

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

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

输入格式

共一行。

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

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

输出格式

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

输入输出样例

输入 #1
8
186 186 150 200 160 130 197 220
输出 #1
4

 

分析:

  此题首先可以判断出它是两个单调升序列,从开头向后,和从后向前,类似于 拦截导弹 那道题。

  本题的算法是动态规划的一个好题,从下面的代码,可以看出此题的解法复合了动态规划的把大问题化成小问题来做,而且没有每次重新做已经做过的任务,类似于数据结构种的一个记录表。

 

代码如下:

  

 1 #include<iostream>
 2 using namespace std;
 3 #include<algorithm>
 4 int n,a[105],f1[105],f2[105],ans;
 5 int main(){
 6 
 7     cin>>n;
 8     for(int i=1;i<=n;i++) cin>>a[i];
 9     a[0]=0;
10     for(int i=1;i<=n;i++)//从1到n求最长升 
11         for(int j=0;j<i;j++) {
12             // cout<<"a[j]= "<<a[j]<<" a[i]= "<<a[i]<<" f1[i] = "<<f1[i]<<endl;
13             if(a[i]>a[j]) 
14                 f1[i]=max(f1[i],f1[j]+1);
15         }
16     a[n+1]=0;
17     cout<<endl<<endl;
18     for(int i=n;i;i--)//从n到1求最长升 
19         for(int j=n+1;j>i;j--) 
20             if(a[i]>a[j]) 
21                 f2[i]=max(f2[i],f2[j]+1);
22     for(int i=1;i<=n;i++) 
23         ans=max(f1[i]+f2[i]-1,ans);//枚举Ti,从1到Ti的最长升+从TK到Ti的最长升-1(Ti被加了两次) 
24     cout<<n-ans<<endl;
25     return 0;
26 }

 

posted @ 2020-04-21 01:46  关注我更新论文解读  阅读(332)  评论(0编辑  收藏  举报