P1091 合唱队形(LIS)
题目描述
NNN位同学站成一排,音乐老师要请其中的(N−KN-KN−K)位同学出列,使得剩下的KKK位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K1,2,…,K1,2,…,K,他们的身高分别为T1,T2,…,TKT_1,T_2,…,T_KT1,T2,…,TK, 则他们的身高满足T1<...<Ti>Ti+1>…>TK(1≤i≤K)T_1<...<T_i>T_{i+1}>…>T_K(1 \le i \le K)T1<...<Ti>Ti+1>…>TK(1≤i≤K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入输出格式
输入格式:
共二行。
第一行是一个整数N(2≤N≤100)N(2 \le N \le 100)N(2≤N≤100),表示同学的总数。
第二行有nnn个整数,用空格分隔,第iii个整数Ti(130≤Ti≤230)T_i(130 \le T_i \le 230)Ti(130≤Ti≤230)是第iii位同学的身高(厘米)。
输出格式:
一个整数,最少需要几位同学出列。
输入输出样例
题意:
给你一个队列,你要求出来满足,不能改变序列中每个数的位置
1、全升子序列
2、全降子序列
3、先升后降子序列
解法:
就是正着反着各求一次LIS,然后再枚举i的值就行了
注意:长度为len的序列的LIS不一定是dp[len],而是再dp[初始]-------dp[len],之间取最大值
上代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=1005; 7 int v1[maxn],dp1[maxn],dp2[maxn],v2[maxn]; 8 void dp(int n,int dp[maxn],int v[maxn]) 9 { 10 for(int i=1;i<=n;++i) 11 { 12 dp[i]=1; 13 for(int j=1;j<i;++j) 14 { 15 if(v[j]<v[i] && dp[j]+1>dp[i]) 16 { 17 dp[i]=dp[j]+1; 18 } 19 20 } 21 //dp[i]=maxx+1; 22 } 23 } 24 int main() 25 { 26 int n; 27 scanf("%d",&n); 28 for(int i=1;i<=n;++i) 29 scanf("%d",&v1[i]); 30 dp(n,dp1,v1); 31 int m=0; 32 for(int i=n;i>0;--i) 33 { 34 v2[++m]=v1[i]; 35 } 36 dp(n,dp2,v2); 37 int sum=0,sum1=0,sum2=0; 38 for(int i=1;i<=n;++i) 39 { 40 sum1=sum2=0; 41 for(int j=1;j<=i;++j) 42 sum1=max(sum1,dp1[j]); 43 for(int j=1;j<=n-i;++j) 44 sum2=max(sum2,dp2[j]); 45 sum=max(sum,sum1+sum2); 46 } 47 for(int i=1;i<=n;++i) 48 { 49 sum1=sum2=0; 50 for(int j=1;j<=n-i;++j) 51 sum1=max(sum1,dp1[j]); 52 for(int j=1;j<=i;++j) 53 sum2=max(sum2,dp2[j]); 54 sum=max(sum,sum1+sum2); 55 } 56 printf("%d\n",n-sum); 57 }