• 合唱队形算法问题记录(大佬代码是C++,但是主要是看解题思路)


    牛客网上的一个华为机试题,看完之后没思路,然后看了一个人的讲解,觉得思路很好,就在这里记录一下,题目如下:

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

    说明:

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

    我的附加说明:剩下的人你是不准去调整他们的位置的。这也是这个题的最难点,如果允许调整,那就so easy了(最大值只能有一个,其他值最多有2个,就是个简单的剔除过多数据的问题了。。。)

    eg:

    输入:

    8
    186 186 150 200 160 130 197 200

    输出:

    4

    思路如下:

    首先计算每个数在最大递增子串中的位置

    186  186  150  200  160  130  197  200   quene

    1      1      1      2       2      1      3     4       递增计数

    然后计算每个数在反向最大递减子串中的位置--->计算反向后每个数在最大递增子串中的位置

    200  197  130  160  200  150  186  186   反向quene

    1      1      1       2     3      2      3       3      递减计数

    然后将每个数的递增计数和递减计数相加

    186  186  150  200  160  130  197  200   quene

    1      1      1      2       2     1      3      4       递增计数

    3      3      2      3       2     1      1      1       递减计数

    4      4      3      5       4     2      4      5       每个数在所在队列的人数+1(自己在递增和递减中被重复计算)

    如160这个数

    在递增队列中有2个人数

    150  160

    在递减队列中有2个人数

    160  130

    那么160所在队列中就有3个人

    150  160  130

    每个数的所在队列人数表达就是这个意思

    总人数 - 该数所在队列人数 = 需要出队的人数

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
     
    void calIncSub(vector<int> quene, vector<int> &Num){
        for(int i=1;i<quene.size();i++)
            for(int j=i-1;j>=0;j--)
                if(quene[j]<quene[i] && Num[i]<Num[j]+1)  //找到前面比当前小的,且【能获得的最大子串计数】
                    Num[i]=Num[j]+1;
    }
     
    int main(){
        int n;
        int h;
         
        while(cin>>n){
            vector<int> quene;
            vector<int> incNum(n,1);  //初始化为n个1
            vector<int> decNum(n,1); 
            vector<int> totalNum;
            for(int i=0;i<n;i++){
                cin >> h;
                quene.push_back(h);   
            }
            calIncSub(quene,incNum);    //找递增子串计数
            reverse(quene.begin(),quene.end()); //翻转,即找反向的子串计数
            calIncSub(quene,decNum);
            reverse(decNum.begin(),decNum.end());   //反向递增即正向递减
            int max=0;
            for(int i=0;i<n;i++){
                totalNum.push_back(incNum[i]+decNum[i]);
                if(totalNum[i]>max)
                    max=totalNum[i];
            }
            cout << n-max+1 <<endl;
        }  
        return 0;
    }
  • 相关阅读:
    poj 3280 Cheapest Palindrome(区间DP)
    POJ 2392 Space Elevator(多重背包)
    HDU 1285 定比赛名次(拓扑排序)
    HDU 2680 Choose the best route(最短路)
    hdu 2899 Strange fuction (三分)
    HDU 4540 威威猫系列故事――打地鼠(DP)
    HDU 3485 Count 101(递推)
    POJ 1315 Don't Get Rooked(dfs)
    脱离eclipse,手动写一个servlet
    解析xml,几种方式
  • 原文地址:https://www.cnblogs.com/gsp1004/p/11117822.html
Copyright © 2020-2023  润新知