您的位置:首页 > 其它

动态规划训练23 [Making the Grade POJ - 3666 ]

2017-06-24 22:00 302 查看


Making the Grade

 POJ
- 3666 

这道题目有点意思。

我们定义dp[i][j]表示的含义是把包含前i个元素的子序列变成非递减的子序列,并且最后一个元素变成j所需要耗费的最小代价

那么状态转移方程可以写出来就是:

dp[i][j] = min(dp[i-1][k] + abs(num[i] - j)) 其中 0<= k <= j

这个方程很简单对吧,但是问题来了

这样的话,空间复杂度显然会超,而且时间复杂度也会超

那么我们来考虑一下优化问题

首先进行空间优化,由于最多只有2000个元素,所以说不同高度的值最多也只能有2000个,那么我们对高度做个离散化,就很容易解决MLE的问题了。

下面的问题回到了时间上,由于时间是O(n3)的,而要在限定时间内完成,我们可以把时间优化到O(n2)

注意到我们在状态转移方程里,花了O(n)的时间去求了k不超过j时候的dp[i-1][k]的最小值。其实我们可以开一个数组MN[i][j]里面恰好就存不超过j时候的dp[i-1][k]的最小值。

在动态规划的过程中进行维护这个数组就OK了

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int MAX = 2005;
const int INF = 1e9;
int a[MAX];
int ss[MAX];
int dp[MAX][MAX];
int MN[MAX][MAX];
int main(){
int N;
scanf("%d",&N);
for(int i = 0;i < N;i++){
scanf("%d",&a[i]);
ss[i] = a[i];
}
sort(ss,ss+N);
int un = unique(ss,ss+N) - ss;
for(int i = 0;i < N;i++){
a[i] = lower_bound(ss,ss+un,a[i]) - ss;
}
for(int i = 0;i < un;i++){
dp[0][i] = abs(ss[i] - ss[a[0]]);
MN[0][i] = min((i == 0? 0 :MN[0][i-1]),dp[0][i]);
}
for(int i = 1;i < N;i++){
dp[i][0] = dp[i-1][0] + abs(ss[0] - ss[a[i]]);
MN[i][0] = dp[i][0];
for(int j = 1;j < un;j++){
dp[i][j] = INF;
//for(int k = 0;k <= j;k++)
//dp[i][j] = min(dp[i][j],dp[i-1][k] + abs(ss[a[i]] - ss[j]));
dp[i][j] = min(dp[i][j],MN[i-1][j] + abs(ss[a[i]] - ss[j]));
MN[i][j] = min(MN[i][j-1],dp[i][j]);
}
}
int ans = INF;
for(int i = 0;i < un;i++){
ans = min(ans,dp[N-1][i]);
}
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息