【题意】
有n块高低不同的地面,每让一块高度改变1则需支付1的代价,问将地面高度变为不上升或不下降序列所需最小代价
【输入】
第一行一个n
接下来n行每行一个数字表示该块地面的高度
【输出】
一个数字,表示最小代价
离散高度后dp
用f[i][j]表示考虑钱i块地面,当前地面高度离散后为j的所需最小代价
f[i][j]=min(f[i-1][k]+abs(h[i]-num[j]))(若为上升序列则k<=j,若为下降序列则k>=j)
枚举k比较慢所以预处理一下
由于f[i]的取值只跟f[i-1]有关,所以运用滚动数字
program poj3666; var n,i,j,k,tot,o,ans:longint; h,dl,num,min:array [0..2001] of longint; f:array [0..1,0..2001] of longint; procedure swap (var a,b:longint); var i:longint; begin i:=a; a:=b; b:=i; end; procedure qsort (s,e:longint); var i,j,k:longint; begin if s>=e then exit; i:=s; j:=e; k:=dl[(s+e) div 2]; while i<=j do begin while dl[i]<k do inc(i); while dl[j]>k do dec(j); if i>j then break; swap(dl[i],dl[j]); inc(i); dec(j); end; qsort(s,j); qsort(i,e); end; begin read(n); for i:=1 to n do read(h[i]); for i:=1 to n do dl[i]:=h[i]; qsort(1,n); k:=0; dl[0]:=-maxlongint; for i:=1 to n do if dl[i]<>dl[k] then begin inc(tot); num[tot]:=dl[i]; k:=i; end; ans:=maxlongint; fillchar(f,sizeof(f),0); o:=0; for i:=1 to n do begin o:=1-o; min[0]:=maxlongint; for j:=1 to tot do begin min[j]:=min[j-1]; if f[1-o,j]<min[j] then min[j]:=f[1-o,j]; end; for j:=1 to tot do f[o,j]:=min[j]+abs(h[i]-num[j]); end; for i:=1 to tot do if f[o,i]<ans then ans:=f[o,i]; fillchar(f,sizeof(f),0); o:=0; for i:=1 to n do begin o:=1-o; min[tot+1]:=maxlongint; for j:=tot downto 1 do begin min[j]:=min[j+1]; if f[1-o,j]<min[j] then min[j]:=f[1-o,j]; end; for j:=1 to tot do f[o,j]:=min[j]+abs(h[i]-num[j]); end; for i:=1 to tot do if f[o,i]<ans then ans:=f[o,i]; writeln(ans); end.