合唱队形【DP】

> Description
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<…Ti+1>…>TK(1<=i<=K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。


> Input
输入的第一行是一个整数N(2<=N<=100),表示同学的总数。第二行有n个整数,用空格分隔,第i个整数Ti(130<=Ti<=230)是第i位同学的身高(厘米)。


> Output
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。


> Sample Input
8
186 186 150 200 160 130 197 220


> Sample Output
4


> 解题思路
(代码十分的丑陋,各位还是不要看了)
还是用动态规划解题。
其实这一道题就是最长不下降序列求最长不下降序列的变形,只是分为了两段不同方向的,然后把它加到一起又开始令人秃头了,表示调这里调了超级久。。。


> 代码

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=101;
int y,a[maxn],f[maxn][maxn],n,ans=maxn;
//y为临时变量算出第二段的最大数,a存初始身高,f存最长不下降序列,ans算出最大数。
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	 scanf("%d",&a[i]);
	//读入数
	for(int k=1;k<=n;k++)
	//划分阶段,n个数每个数为一个阶段(枚举中心点)
	{
		y=0;
		for(int i=1;i<=k;i++)
        {
        	for(int j=1;j<=i;j++)
		     if(a[j]<a[i]&&f[k][j]>f[k][i]) f[k][i]=f[k][j];
		    f[k][i]++;
        }//求最长不下降序列(左边)
		for(int i=n;i>k;i--)
        {
        	for(int j=i+1;j<=n;j++)
		     if(a[j]<a[i]&&f[k][j]>f[k][i]) f[k][i]=f[k][j];
		    f[k][i]++;
		    if(f[k][i]>y&&a[i]<a[k]) y=f[k][i];
        }//求最长不下降序列(右边)
        f[k][k]+=y;
        //把两边的数累加到中心点
		if(n-f[k][k]<ans) ans=n-f[k][k];
		//算出最大数
	}
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/82810167