华为机试HJ24:合唱队

Posted 翟天保Steven

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了华为机试HJ24:合唱队相关的知识,希望对你有一定的参考价值。

题目描述:

计算最少出列多少位同学,使得剩下的同学排成合唱队形

说明:

N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。 
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK,   则他们的身高满足存在i(1<=i<=K)使得T1<T2<......<Ti-1<Ti>Ti+1>......>TK。 

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

注意:不允许改变队列元素的先后顺序  不要求最高同学左右人数必须相等

请注意处理多组输入输出!

备注:

1<=N<=3000

输入描述:

有多组用例,每组都包含两行数据,第一行是同学的总数N,第二行是N位同学的身高,以空格隔开

输出描述:

最少需要几位同学出列

示例:

输入:

8

186 186 150 200 160 130 197 200

输出:

4

解题思路:

这是一个最长子序列问题,也是动态规划问题。在不影响原先排列的前提下,抽出最少多少个人可以组成合唱序列;首先从左往右,计算从低到高截止到每个人所能组成的最大子序列;再从右向左,计算从低到高截止到每个人所能组成的最大子序列;这两个子序列的数值相加再减一,因为本人加了两次,这样得到的就是所能组成合唱序列的最大人数,那么抽出的最少人数就是总人数减序合唱序列最大人数。

测试代码:

#include <iostream>

using namespace std;

int main()
{
    int number=0;
    int people[3000],left[3000],right[3000];
    while(cin>>number)
    {
        for(int i=0;i<number;++i)
        {
            cin>>people[i];
            left[i]=1;
            for(int j=0;j<i;++j)
            {
                if(people[i]>people[j])
                {
                    left[i]=max(left[i],left[j]+1);
                }
            }
        }
        for(int i=number-1;i>=0;--i)
        {
            right[i]=1;
            for(int j=number-1;j>i;--j)
            {
                if(people[i]>people[j])
                {
                    right[i]=max(right[i],right[j]+1);
                }
            }
        }
        int sum=0;
        for(int i=0;i<number;++i)
        {
            if(left[i]+right[i]-1>sum)
            {
                sum=left[i]+right[i]-1;
            }
        }
        cout<<number-sum<<endl;
    }
    return 0;
}

以上是关于华为机试HJ24:合唱队的主要内容,如果未能解决你的问题,请参考以下文章

华为机试HJ89:24点运算

华为机试HJ67:24点游戏算法

牛客 HJ24 合唱队

华为机试刷题笔记HJ39-判断两个IP是否属于同一子网

HJ24_合唱队_动态规划_打印最少剔除人数_输出任意一列最长队列身高

华为机试-HJ68 成绩排序