POJ 3666(Making the Grade)

题目链接: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 
#include 
#include 
#include 
#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\n",ans);	
	}

	return 0;
}

  

 

你可能感兴趣的:(POJ 3666(Making the Grade))