[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\n", ans); return 0; }