牛客網-網易2018筆試第7題 -合唱(DP問題)


【題目描述】
小Q和牛博士合唱一首歌曲,這首歌曲由n個音調組成,每個音調由一個正整數表示。
對於每個音調要麼由小Q演唱要麼由牛博士演唱,對於一系列音調演唱的難度等於所有相鄰音調變化幅度之和, 例如一個音調序列是8, 8, 13, 12, 那麼它的難度等於|8 - 8| + |13 - 8| + |12 - 13| = 6(其中||表示絕對值)。
現在要對把這n個音調分配給小Q或牛博士,讓他們演唱的難度之和最小,請你算算最小的難度和是多少。
如樣例所示: 小Q選擇演唱{5, 6}難度爲1, 牛博士選擇演唱{1, 2, 1}難度爲2,難度之和爲3,這一個是最小難度和的方案了。

輸入描述

輸入包括兩行,第一行一個正整數n(1 ≤ n ≤ 2000) 第二行n個整數v[i](1 ≤ v[i] ≤ 10^6), 表示每個音調。

輸出描述

輸出一個整數,表示小Q和牛博士演唱最小的難度和是多少。

【示例】

【輸入】
5
1 5 6 2 1
【輸出】
3

【問題分析】(思路來源於牛客網暱稱 “啊打頭的名字會排在前面” 用戶,在此非常感謝)

子問題的話還是dp[j][i] 表示兩個人唱的最後兩個音符的位置是i和j。其中(j<i)
研究dp[j][i]的轉移方程:
如果j+1==i; 比如dp[3][4]那麼,其可以到達它的狀態有{dp[0][3],dp[1][3],dp[2][3],還有一種情況是3的前面全是由一個人唱的},計算這些前置狀態+本次決策的收益並進行比較。
如果j+1!=i; 說明這個狀態只能由dp[j][i-1]達到,比如dp[3][5] 它的前狀態一定是dp[3][4]

【代碼】

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<memory.h>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
 
#define mem(array)  memset((array),0,sizeof((array)))
#define Qsort(array,len,cmp) qsort(array,len,sizeof(array[0]),cmp)
 
#define inf 0x7fffffff
#define MAXN 10+2000
 
using namespace std;
 
int dp[MAXN][MAXN];
int v[MAXN];
 
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",tdout);
    int n;
    while(cin>>n){
        mem(v);
        for(int i = 1; i <= n; ++i)
            scanf("%d",&v[i]);
        mem(dp); 
        for(int i = 1; i <= n; ++i){
            for(int j = 0; j < i; ++j){
                if(j+1 == i){
                    dp[j][i] = dp[0][j];
                    for(int k = 1; k < j; ++k){
                        dp[j][i] = min(dp[j][i],dp[k][j] + abs(v[k]-v[i]));
                    }
                }
                else{
                    dp[j][i] = dp[j][i-1] + abs(v[i-1]-v[i]);
                }
            }
        }
        int ans = dp[0][n];
        for(int i = 1; i < n; ++i)
            ans = min(ans,dp[i][n]);
        cout<<ans<<endl;
    }
    return 0;
}

 

題目來源於 牛客網

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章