算法练习题 2 合唱队

题目

题目描述

N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。

合唱队形定义:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK,

则他们的身高满足T1 < T2 < … < Ti, Ti > Ti+1 > … > TK (1 <= i <= K)。
要求:已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入

输入的第一行是一个整数N,表示同学的总数。第一行有n个整数,用空格分隔,第i个整数Ti是第i位同学的身高(厘米)。

输出

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

解题思路

首先将n个同学的身高存入a[n]中 ,当然数组大小需要大于该值 

【解】假设队中最高的那个人的序列为 i ,那么他左边递增序列与右边递减序的和 列是所有人中最长的

所以我们第一步需要找到每个同学左边递增序列的个数  

例如有8位同学,身高分别为  186 186 150 200 160 130 197 200

递增序列 inc[n] 的求法,每一个数只需要看每个数的序列值,设0<j<i<n , 若 a[j] < a[i] ,那么inc[i] = inc[j] + 1; 后面的数永远会添加之前出现的递增子串后,

而且这里注意,我们最后得到inc[i] 应该是之前所有的inc[j]中最大那个+1

186 186 150 200 160 130 197 200
1 1 1 2 2 1 3 4

 

 

递减序列 dec[n] 的求法和上面大同小异,如法炮制,只不过是从右往左找递增

186 186 150 200 160 130 197 200
3 3 2 3 2 1 1 1

 

 

递增和递减序列都将自身算在内了,所以我们算总合唱团长度时需要减去自身的重复

代码示意

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int N;
    int array[5000];
    while(cin>>N)
    {
        int i,j; 
        int inc[5000],dec[5000];//递增和递减序列
        for(i = 0;i<N;i++)
        {
            cin>>array[i];
            inc[i] = 1;
            dec[i] = 1;
        }
        if(N<=1) 
        {
            cout<<0<<endl;
            continue;
        }
        for(i = 0;i<N;i++)//求递增子串序列
        {
            for(j = 0;j<i;j++)
            {
                if(array[i]>array[j]&&inc[j]+1>inc[i]) inc[i]=inc[j]+1;
            }
        }
        
        for(i = N-1;i>=0;i--)//求递减子串序列
        {
            for(j = N-1;j>i;j--)
            {
                if(array[i]>array[j]&&dec[j]+1>dec[i]) dec[i] = dec[j]+1;
            }
        }
        int max = 0;
        for(i = 0;i<N;i++)
        {
            if(max < (inc[i]+dec[i]-1)) max = inc[i]+ dec[i]-1;//求最大合唱序列人数
        }
        cout<<N-max<<endl;
    }
    return 0;
}

 

posted @ 2020-04-12 23:47  SD117  阅读(408)  评论(0编辑  收藏  举报