[BZOJ1592] [Usaco2008 Feb]Making the Grade 路面修整(DP)

传送门

有个结论,每一个位置修改高度后的数,一定是原来在这个数列中出现过的数

因为最终结果要么不递增要么不递减,

不递增的话,

  如果x1 >= x2那么不用动,如果x1 < x2,把x1变成x2的代价最小

不递减同理

输入数组a后,把a数组复制一份放到b中,并将b排序

f[i][j]表示前i个,当前修改为b[j]的最优解

dp的时候前缀和优化一下即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2001
#define abs(x) ((x) < 0 ? -(x) : (x))
#define min(x, y) ((x) < (y) ? (x) : (y))

int n, ans = ~(1 << 31);
int a[N], b[N], f[N][N][2];
//f[i][j]表示前i个数,第i个数为b[j]的最优解
//0表示不下降,1表示不上升 

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
	return x * f;
}

int main()
{
	int i, j, sum;
	n = read();
	for(i = 1; i <= n; i++) a[i] = b[i] = read();
	std::sort(b + 1, b + n + 1);
	memset(f, 127, sizeof(f));
	memset(f[0], 0, sizeof(f[0]));
	for(i = 1; i <= n; i++)
	{
		sum = ~(1 << 31);
		for(j = 1; j <= n; j++)
		{
			sum = min(sum, f[i - 1][j][0]);
			f[i][j][0] = min(f[i][j][0], sum + abs(a[i] - b[j]));
		}
		sum = ~(1 << 31);
		for(j = n; j >= 1; j--)
		{
			sum = min(sum, f[i - 1][j][1]);
			f[i][j][1] = min(f[i][j][1], sum + abs(a[i] - b[j]));
		}
	}
	for(i = 1; i <= n; i++)
		ans = min(ans, min(f[n][i][0], f[n][i][1]));
	printf("%d
", ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhenghaotian/p/7515970.html