【題目描述】
小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;
}
題目來源於 牛客網