N位同学站成一列,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样一种队形,设K位同学从左到右依次编号为1、2...K,他们的身高分别为T1,T2,...,Tk,则他们的身高满足T1 <...< Ti < Ti+1>...>TK(1<=i<=K).
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入文件chorus.in的第一行是一个整数N(2<=N<=100),表示同学的总数。第一行有n个整数,用空格分隔,第i个整数Ti(130<=Ti<=230)是第i位同学的身高(厘米)。
输出文件chorus.out包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
8
186 186 150 200 160 130 197 220
4
问题分析:出列人数最少,也就是留的人数最多,也就是序列最长,这样问题也就变成了最长上升子序列和最长下降子序列的问题。
设T[i]为序列中的第i个人,对于T[i]分别求T[0,...i]的最长上升子序列长度len1[i]和T[i+1,...N]的最长下降子序列len2[i];则出队的同学数目为N-max(len1[i]+len2[i]-1),0<=i<=N-1.此算法的时间复杂度为O(N3),空间复杂度为O(N).
其实只要对T[i](0<= i< N)求一次最长上升子序列长度len1[i]和一次最长下降子序列长度len2[i].如此时间复杂度可为O(N2),空间复杂度仍为O(N).
1 void chorus(int a[],int len) {
2 int *len1=new int[len];
3 int *len2=new int[len];
4 int i=0;
5 for(;i<len;i++) {
6 len1[i]=1;
7 len2[i]=1;
8 }
9 for(i=1;i<len;i++)
10 for(int j=0;j<i;j++) {
11 if(a[j]<a[i] &&(len1[j]+1>len1[i]))
12 len1[i]=len1[j]+1;
13 if(a[j]>a[i] && (len2[j]+1<len2[i]))
14 len2[i]=len2[j]+1;
15 }
16 int maxlen=len1[0]+len2[0];
17 for(i=1;i<len;i++)
18 if(len1[i]+len2[i]>maxlen) {
19 // cout<<i<<endl;
20 maxlen=len1[i]+len2[i];
21 }
22 cout<<len-maxlen+1<<endl;
23 delete len1;
24 delete len2;
25 }
转自:http://liuyangxdgs.blog.163.com/blog/static/2913776320111144438848/