题目链接:http://poj.org/problem?id=3666
题意:农夫约翰想修一条尽量平缓的路,路的每一段海拔是A_i,修理后是B_i,花费|A_i – B_i|,求最小花费。平缓的意思是海拔单调增或单调减(非严格)
思路:
这是一道动态规划的问题,突破口是:每个数最后必然是原序列中的数。
用dp[i][j]表示:前i个数构成的序列,这个序列最大值为j,dp[i][j]的值代表相应的cost。
状态转移方程:dp[i][j]=abs(j-w[i])+min(dp[i-1][k]) (k<=j)
网上很多都是说用离散化的思想,但是一直不是很理解这是什么意思,就是将序列排序一下,然后用位置的前后关系来制定其值,这样时间复杂度变成O(N^2).
不是很理解别人的思路,我就想的朴素一点,大概就是把for 循坏 j 的数值的取值范围缩小一些
ac代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define MAX_N 2005
using namespace std;
typedef long long ll;
ll a[MAX_N],b[MAX_N];
ll dp[MAX_N][MAX_N];
int n;
int main(void){
while(~scanf("%d",&n)){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
for(int i=1;i<=n;i++){
ll mn=dp[i-1][1];
for(int j=1;j<=n;j++){
mn=min(mn,dp[i-1][j]);
dp[i][j]=abs(a[i]-b[j])+mn;
}
}
ll ans=dp[n][1];
for(int i=2;i<=n;i++)
ans=min(ans,dp[n][i]);
printf("%lld
",ans);
}
return 0;
}