动规——合唱队形
Posted F.r.a.n.k.y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动规——合唱队形相关的知识,希望对你有一定的参考价值。
这是以前写的==转过来qwq
【例8】合唱队形
【问题描述】
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK,则他们的身高满足T1 < T2 < … < Ti , 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
【数据规模】
对于50%的数据,保证有n ≤ 20;对于全部的数据,保证有n≤100。
【算法分析】
我们按照由左而右和由右而左的顺序,将n个同学的身高排成数列。如何分别在这两个数列中寻求递增的、未必连续的最长子序列,就成为问题的关键。设
a 为身高序列,其中a[i]为同学i的身高;
b 为由左而右身高递增的人数序列,其中 b[i]为同学1‥同学i间(包括同学i)身高满足递增顺序的最多人数。显然b[i]={b[j]|同学j的身高<同学i的身高}+1;
c为由右而左身高递增的人数序列,其中c[i]为同学n‥同学i间(包括同学i)身高满足递增顺序的最多人数。显然c[i]={c[j]|同学j的身高<同学i的身高}+1;
由上述状态转移方程可知,计算合唱队形的问题具备了最优子结构性质(要使b[i]和c[i]最大,子问题的解b[j]和c[k]必须最大(1≤j≤i-1 ,i+1≤k≤n))和重迭子问题的性质(为求得b[i]和c[i],必须一一查阅子问题的解b[1]‥b[i-1]和c[i+1]‥c[n]),因此可采用动态程序设计的方法求解。
显然,合唱队的人数为(公式中同学i被重复计算,因此减1),n减去合唱队人数即为解。
【AC】
#include<iostream>
#include<cstdio>
using namespace std;
int a[500],b[500],c[500],i,j,n,m;
int main()
{
scanf("%d",&n);
for(i=1; i<=n; i++)
cin>>a[i];
for(i=1; i<=n; i++)
{
c[i]=1;
for(j=1; j<=i-1; j++)
if((a[j]<a[i])&&(c[j]+1>c[i]))
c[i]=c[j]+1;
}
for(i=n; i>=1; i--)
{
b[i]=1;
for(j=i+1; j<=n; j++)
if((a[j]<a[i])&&(b[j]+1>b[i]))
b[i]=b[j]+1;
}
for(i=1; i<=n; i++)
if(c[i]+b[i]>m)
m=c[i]+b[i];
printf("%d",n-m+1);
}
以上是关于动规——合唱队形的主要内容,如果未能解决你的问题,请参考以下文章