题目大意:
农夫约翰想改造一条路,原来的路的每一段海拔是A_i,修理后是B_i,花费|A_i – B_i|。我们要求修好的路是单调不升或者单调不降的。求最小花费。
解题思路:
dp+离散
设f[i][j]表示完成前i个数的构造,其中B[i]=j时,S的最小值
F[i][j]=min(F[i−1,k]+|Ai−j|)(0<=k<=j)
F
[
i
]
[
j
]
=
m
i
n
(
F
[
i
−
1
,
k
]
+
|
A
i
−
j
|
)
(
0
<=
k
<=
j
)
我们把A序列中出现的数进行离散化,把dp状态中第二维j的范围降低到O(N)。
然后因O(1)可以实现转移,故该算法时间复杂度为O(N 2 2 )
Accepted code:
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define N 2005
#define r(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,m,t[N],a[N],b[N],f[N][N];
inline void read(int &f) {
int ag=1;f=0; char c=getchar();
while(!isdigit(c)) {if (c=='-') ag=-1; c=getchar();}
while(isdigit(c)){f=(f<<1)+(f<<3)+c-48;c=getchar();}
f*=ag;return;
}
inline void init() {
read(n);
r(i,1,n)
read(a[i]),t[i]=a[i];
sort(t+1,t+n+1);
int len=-2147483647;
r(i,1,n)
if (t[i]!=len) b[++m]=t[i],len=t[i];
}
int dp() {
r(i,1,n) {
f[i][1]=f[i-1][1]+abs(a[i]-b[1]);
r(j,2,m)
f[i][j]=min(f[i][j-1],f[i-1][j]+abs(a[i]-b[j]));
}
return f[n][m];
}
int dp_main() {
int Ans=dp();
memset(f,0,sizeof(f));
r(i,1,n/2) swap(a[i],a[n-i+1]);
return min(dp(),Ans);
}
void print(int x) {
if (x>9) print(x/10); putchar(x%10+48); return;
}
int main() {
init();
print(dp_main());
}