動態規劃入門H - 合唱隊形 (最優子序列的另外一個應用,這裏是最優遞增和最優遞減子序列的結合)

題目:H - 合唱隊形
N位同窗站成一排,音樂老師要請其中的(N-K)位同窗出列,使得剩下的K位同窗不交換位置就能排成合唱隊形。
合唱隊形是指這樣的一種隊形:設K位同窗從左到右依次編號爲1, 2, …, K,他們的身高分別爲T1, T2, …, TK,則他們的身高知足T1 < T2 < … < Ti , Ti > Ti+1 > … > TK (1 <= i <= K)。
你的任務是,已知全部N位同窗的身高,計算最少須要幾位同窗出列,能夠使得剩下的同窗排成合唱隊形。
Input
輸入的第一行是一個整數N(2 <= N <= 100),表示同窗的總數。第一行有n個整數,用空格分隔,第i個整數Ti(130 <= Ti <= 230)是第i位同窗的身高(釐米)。
Output
輸出包括一行,這一行只包含一個整數,就是最少須要幾位同窗出列。
Sample Input
8
186 186 150 200 160 130 197 220
Sample Output
4數組

思路:用兩個dp數組,一個用來存正向遞增,一個用來存反向遞增,而後最後對應相加,再求一個最大的子序列,(這裏要求的是寬度,不是數值的和,因此都再清0以後,有相應的則進行+1,具體看代碼就知道了);code

注意:避免在兩次尋找最優子序列的時候將其自己給重複進行相加了!!!string

新技巧:經過找正向與反向的雙向遞增子序列,這樣就能夠解決有峯值的最優子序列問題;io

代碼:技巧

#include<stdio.h>
#include<string.h>

int a[105],dp_left[105];
int dp_right[105],dp[105];

int main()
{
    int n,i,j,s;
    while(scanf("%d",&n)!=EOF){
        memset(dp_left,0,sizeof(dp_left ));
        memset(dp_right,0,sizeof(dp_right ));

        for(i=0;i<n;++i)
            scanf("%d",&a[i]);
        for(i=1;i<n;++i){
            for(j=0;j<i;j++){
                if(a[i]>a[j])
                    dp_left[i]=dp_left[i]>(dp_left[j]+1)?dp_left[i]:(dp_left[j]+1);  //就是這個位置,只須要進行加的操做便可;
            }
        }
        for(i=n-1;i>=0;--i){
            for(j=n-1;j>i;j--){
                if(a[i]>a[j])
                    dp_right[i]=dp_right[i]>(dp_right[j]+1)?dp_right[i]:(dp_right[j]+1);
            }
        }
        for(i=0;i<n;++i)
            dp[i]=dp_left[i]+dp_right[i]+1;//個人操做是一開始就沒有算其自己
        int k=0;                        //全部在這個求和的時候要加上其自己
        for(i=1;i<n;++i)
            if(dp[k]<dp[i])
            k=i;
        s=n-dp[k];
        printf("%d\n",s);

    }
    return 0;
}
相關文章
相關標籤/搜索