http://www.wikioi.com/problem/2572/
赶脚挺不错的一道DP。。。。
抄过来。
思路分析:
显然(?)修整后的路面一定是原路面的某个值。
创建新数组c等于原数组,然后将c排序,f[i][j]表示原数组前i个数变为单调上升,且i是c中的第j个数。
f[i][j]=min(f[i-1][k]+abs(a[i]-c[j]));
但是还可以优化,用一个g[i][j]表示f[i][k]中的最优值
g[i][j]=min(g[i][j-1],f[i][j])
f[i][j]=g[i-1][j]+abs(a[i]-a[j]);
边界:
f[0][i]=g[0][i]=0;
g[i][0]=maxlongint;
结果:
g[n][n];
对于单调上升与递减,求出某个后,将原数组倒过来在dp一次即可。
代码(Pascal):
Uses math;
Var a,tmp,c:array[0..2000] of longint;
n,ans:longint;
g,f:array[0..2000,0..2000] of longint;
Procedure swap(var a,b:longint);Var t:longint; begin t:=a; a:=b; b:=t; end;
Procedure qsort(l,r:longint);
Var i,j,x:longint;
Begin
i:=l; j:=r;
x:=a[(l+r) shr 1];
repeat
while x>a[i] do inc(i);
while x<a[j] do dec(j);
If i<=j then
begin
swap(a[i],a[j]);
inc(i); dec(j)
end;
Until i>j;
If i<r then qsort(i,r);
If l<j then qsort(l,j);
End;
Procedure dp;
Var i,j:longint;
Begin
For i:=1 to n do g[i,0]:=maxlongint;
For i:=1 to n do
For j:=1 to n do
Begin
f[i,j]:=g[i-1,j]+abs(a[i]-c[j]);
g[i,j]:=min(f[i,j],g[i,j-1]);
End;
ans:=min(ans,g[n,n]);
End;
Procedure main;
Var i:longint;
Begin
ans:=maxlongint;
readln(n);
For i:=1 to n do read(a[i]);
tmp:=a;
Qsort(1,n);
c:=a; a:=tmp;
dp;
tmp:=c;
For i:=1 to n do c[i]:=tmp[n-i+1];
dp;
writeln(ans);
readln;
End;
Begin
main;
End.