华为机试-合唱队(较难)
合唱队
http://www.nowcoder.com/practice/6d9d69e3898f45169a441632b325c7b4
题目描述
计算最少出列多少位同学,使得剩下的同学排成合唱队形
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<=K)使得T1<T2<......<Ti-1<ti>Ti+1>......>TK。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。</ti>
注意不允许改变队列元素的先后顺序
请注意处理多组输入输出!
输入
8
186 186 150 200 160 130 197 200
输出
4
需要出列的同学最少 = 保留下来的同学最多。
最后排成的合唱队是△先递增再递减的,中间会有一个最高的中心同学i。
当中心同学i左边的同学+右边同学最多的时候,保留下的同学最多。
即i左边的最长递增子序列 + i右边的最长递减子序列最大的时候是最优解。
先求i处最长递增子序列的个数:dp_up[i]=max(dp_up[i],dp_up[j]+1); 其中j<i;从左往右循环。
再求i处最长递减子序列的个数:dp_down[i]=max(dp_down[i],dp_down[j]+1);其中j>i;从右往左循环。
当i处dp_up[i]+dp_down[i]最大时,i就是中心同学,此时队列中人数dp_up[i]+dp_down[i]-1
出列的人数:总人数num-(dp_up[i]+dp_down[i]-1)
#include<iostream>
#include<vector>
using namespace std;
int main(){
int num;
while(cin>>num){
vector<int> temp;
vector<int> dp_up(num,1);
vector<int> dp_down(num,1);
for(int i=0;i<num;i++){
int a;
cin>>a;
temp.push_back(a);
}
//dp_up[i]最长上升子序列个数
for(int i=1;i<temp.size();i++){
for(int j=i-1;j>=0;j--){
if(temp[j]<temp[i]){
dp_up[i]=max(dp_up[i],dp_up[j]+1);
}
}
}
//dp_down[i]最长下降子序列个数
for(int i=temp.size()-2;i>=0;i--){
for(int j=i+1;j<temp.size();j++){
if(temp[j]<temp[i]){
dp_down[i]=max(dp_down[i],dp_down[j]+1);
}
}
}
int maxvalue=0;
for(int i=0;i<temp.size();i++){
if(dp_up[i]+dp_down[i]>maxvalue)
maxvalue=dp_up[i]+dp_down[i];
}
cout<<num-(maxvalue-1)<<endl;
}
}