您的位置:首页 > 其它

九度oj-合唱队形

2018-04-06 10:44 141 查看
转载自:这位博主~
题目:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK,则他们的身高满足T1 < T2 < … < Ti , Ti > Ti+1 > … > TK (1 <= i <= K)。你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

[b]输入描述:[/b]输入的第一行是一个整数N(2 <= N <= 100),表示同学的总数。第一行有n个整数,用空格分隔,第i个整数Ti(130 <= Ti <= 230)是第i位同学的身高(厘米)。
[b]输出描述:[/b]可能包括多组测试数据,对于每组数据,输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
示例1

输入:

8
186 186 150 200 160 130 197 220

输出:

4
解题思路:
动态规划博大精深!!首先这又是个求最长递增序列的问题,我们可以把问题分成两部分,首先是从起点到当前点递增,然后是当前点到末尾点递减。然后分别求出两部分的最长序列个数,结果就是总长度减去这两部分的和(其中注意当前点被计算了两次)。其中计算从当前点到末位点递减序列时,要利用末位点到当前点递增这个等价的条件,因为此时末尾点的状态在当前点的状态之前。注意求解过程中,思路一定要清晰!# include<stdio.h>
int max(int a,int b)
{
return a>b?a:b;
}

int main()
{
int n,i,j;
int dp2[1000];
int a[1000];
int dp1[1000];

while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
//初始化
for(i=0;i<n;i++)
{
dp1[i]=0;
dp2[i]=0;
}

//找到以i结尾的最长递增子序列
for(i=0;i<n;i++)
{
int tmp1=1;
for(j=0;j<i;j++)
{
if(a[j]<a[i])
tmp1=max(tmp1,dp1[j]+1);
}
dp1[i]=tmp1;
}
/* for(i=0;i<n;i++)
printf("%d ",dp1[i]);
printf("\n");*/
//找到以i开头的最长递减子序列
//等价于以i结尾的反向增序列

for(i=n-1;i>=0;i--)
{
int tmp2=1;
for(j=n-1;j>i;j--)
{
if(a[j]<a[i])
tmp2=max(tmp2,dp2[j]+1);
}
dp2[i]=tmp2;
}

/* for(i=0;i<n;i++)
printf("%d ",dp2[i]);
printf("\n");*/
//判断两者的和

int ans=1;
for(i=0;i<n;i++)
{
if(ans<dp1[i]+dp2[i]-1)
ans=dp1[i]+dp2[i]-1;//dp[i]计算了两遍
}
printf("%d\n",n-ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  九度oj 双向LIS