POJ 3666 Making the Grade DP+离散化思想

Description
A straight dirt road connects two fields on FJ’s farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).
You are given N integers A1, … , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . … , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is
|A1 - B1| + |A2 - B2| + … + |AN - BN |
Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer.
Input
Line 1: A single integer: N
Lines 2…N+1: Line i+1 contains a single integer elevation: Ai
Output
Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.
Sample Input
7
1
3
2
4
5
3
9
Sample Output
3

题目大意:
给定一个序列,序列的长度为n,以最小代价将其变成非严格递增或者非严格递减序列

解题分析:
首先我们会发现,当一个数需要修改时,或者和前一个数字一样,或者和后一个数字一样,这样才能修改量最小。
下面我们以修改成非严格递增序列为例进行考虑:

定义dp[i][j] 表示将原序列中的前i个数修改成最大值为j时的花费
这也意味着新序列中new[i]的值一定为j
可得到动态规划方程式为:
dp[i][j] = min(dp[i-1][k]) + abs(num[i]-j)//abs(num[i]-j)便意味着将new[i]变为j
上式中0=<k<=j  (题目中0 ≤ Ai ≤ 1,000,000,000)

此时的复杂度为O(n*m*m)
这里的m为Ai的最大值 显然TLE

dp[i][j] = min(dp[i-1][k]) + abs(num[i]-j)(0=<k<=j)这里的k无需从0遍历到j,只需要在对 j 进行for循环的时候不断更新一个dp[i-1][ j ]的最小值tmp = min(tmp, dp[i - 1][j]),然后对dp[i][j] = tmp + abs(num[i]-j)即可
这样改进之后即可从本来的时候时间复杂度O(n*m*m)改进为O(n*m)
不过即便是这样,时间复杂度还是难以接受
根据前面所讨论的,当一个数需要修改时,或者和前一个数字一样,或者和后一个数字一样。这样的话j的取值便是原序列中的元素,可根据求的是非严格递增或者非严格递减序列对原序列中的元素进行排序(当然前提是原序列已经得到了保存)作为 j 可能的取值,这样,最终的时间复杂度改进为O(n*n)

AC代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int dp[2001][2001];
int num[2001];
int sorted[2001];
int p;
int solveup() {//修改为非严格递增序列
	sort(sorted + 1, sorted + 1 + p);//从小到大排序
	for (int i = 1; i <= p; i++)dp[0][i] = 0;
	for (int i = 1; i <= p; i++) {
		int tmp = dp[i - 1][1];
		for (int j = 1; j <= p; j++) {
			tmp = min(tmp, dp[i - 1][j]);
			dp[i][j] = tmp + abs(num[i] - sorted[j]);
		}
	}
	int ans = dp[p][1];
	for (int t = 1; t <= p; t++) {
		ans = min(ans, dp[p][t]);
	}
	return ans;
}
bool cmp(int a, int b) { return a > b; }
int solvedown() {//修改为非严格递减序列
	sort(sorted + 1, sorted + 1 + p, cmp);//从大到小排序
	for (int i = 1; i <= p; i++)dp[0][i] = 0;
	for (int i = 1; i <= p; i++) {
		int tmp = dp[i - 1][1];
		for (int j = 1; j <= p; j++) {
			tmp = min(tmp, dp[i - 1][j]);
			dp[i][j] = tmp + abs(num[i] - sorted[j]);
		}
	}
	int ans = dp[p][1];
	for (int t = 1; t <= p; t++) {
		ans = min(ans, dp[p][t]);
	}
	return ans;
}
int main() {
	scanf("%d", &p);
	for (int i = 1; i <= p; i++) {
		scanf("%d", &num[i]);
		sorted[i] = num[i];
	}
	int ans;
	ans = min(solveup(), solvedown());
	cout << ans << endl;
	//system("pause");
}

参考的大神博客:POJ3666 Making the Grade [DP,离散化]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值