您的位置:首页 > 其它

[POJ 3666]Making the Grade[DP]

2016-01-15 19:26 295 查看
题目链接:[POJ 3666]Making the Grade[DP]

题意分析:

含有n个数的序列,允许对序列中的任意一个数加或者减,问:最少更改多少值,使得原序列变成单调递增或者单调递减?

解题思路:

对于一个数字的修改,我们将它修改成序列中有的数是最好的选择(我是靠找不到反例来理解的= =)。那么我们就可以先把这些数字拷贝出来排个序,就有接下来:

设状态dp[i][j]为到第i个数,以b[j]为结尾更改的最少价值。那么有转移方程dp[i][j]=min(dp[i−1][k])+|a[i]−b[j]|(k=0∼j)这个方程是三方的,对于此题显然会T的。注意到min(dp[i-1][k])是前j项的最小值,那么在转移的时候维护这个最小值即可。这样可以降到平方的复杂度。

个人感受:

前n项求和,求最小值等等等,都能这么优化,2333

具体代码如下:

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define ll long long
using namespace std;

const int INF = 0x7f7f7f7f;
const int MAXN = 2e3 + 111;

int a[MAXN], b[MAXN];
int dp[MAXN][MAXN];

bool cmp(int a, int b) {
return a > b;
}

int main()
{
int n; cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i], b[i] = a[i];

sort(b, b + n);
for (int i = 0; i < n; ++i) dp[0][i] = abs(a[0] - b[i]);
int ans1 = INF;
for (int i = 1; i < n; ++i) {
int pre = dp[i - 1][0];
for (int j = 0; j < n; ++j) {
pre = min(pre, dp[i - 1][j]);
dp[i][j] = pre + abs(a[i] - b[j]);
}
}
for (int i = 0; i < n; ++i) {
ans1 = min(ans1, dp[n - 1][i]);
}

sort(b, b + n, cmp);
for (int i = 0; i < n; ++i) dp[n - 1][i] = abs(a[n - 1] - b[i]);
int ans2 = INF;
for (int i = n - 2; i >= 0; --i) {
int pre = dp[i + 1][n - 1];
for (int j = n - 1; j >= 0; --j) {
pre = min(pre, dp[i + 1][j]);
dp[i][j] = pre + abs(a[i] - b[j]);
}
}
for (int i = 0; i < n; ++i) {
ans2 = min(ans2, dp[0][i]);
}

cout << min(ans1, ans2) << '\n';
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: