一道不错的dp题

就是最小修改代价,使序列变为一个非下降序或非上升(由于数据较弱直接求非下降即可,当然非上升非下降本质是一样的)

观察可得到,修改后得到的数列中的元素最后一定都在原序列中;

由此我们可以将原数列排序离散化;

在dp[i,j]表示新序列到第i个元素修改成原序列第j小的数所用的代价

易得dp[i,j]=min(dp[i-1,k])+abs(p[i]-a[j]) (1<=k<=j); a是原数列,p是排序后的

由于n<=1000 看起来这样的方程式O(n^3)会超时;

实际上,我们在处理的时候,完全可以优化成O(n^2);

由于abs(p[i]-a[j])是一个定值,不受k影响,所以我们可以先用dp[i,j]表示min(dp[i-1,k]) (1<=k<=j)

则dp[i,j+1]=min(d[i,j],d[i-1,j]);

最后再集体加上abs(p[i]-a[j])即可实现O(n^2)

 1 var f:array[0..1,0..2010] of longint;
 2     a,p:array[0..2010] of longint;
 3     n,i,k1,k2,j,ans:longint;
 4 
 5 procedure swap(var a,b:longint);
 6   var c:longint;
 7   begin
 8     c:=a;
 9     a:=b;
10     b:=c;
11   end;
12 
13 function min(a,b:longint):longint;
14   begin
15     if a>b then exit(b) else exit(a);
16   end;
17 
18 procedure sort(l,r: longint);
19   var i,j,x: longint;
20   begin
21     i:=l;
22     j:=r;
23     x:=a[(l+r) div 2];
24     repeat
25       while a[i]<x do inc(i);
26       while x<a[j] do dec(j);
27       if not(i>j) then
28       begin
29         swap(a[i],a[j]);
30         inc(i);
31         j:=j-1;
32       end;
33     until i>j;
34     if l<j then sort(l,j);
35     if i<r then sort(i,r);
36   end;
37 
38 begin
39   readln(n);
40   for i:=1 to n do
41   begin
42     readln(a[i]);
43     p[i]:=a[i];
44   end;
45   sort(1,n);
46   k1:=1;
47   k2:=0;
48   for i:=1 to n do
49   begin
50     k1:=k1 xor 1;
51     k2:=k2 xor 1;
52     f[k2,1]:=f[k1,1];
53     for j:=2 to n do
54       f[k2,j]:=min(f[k2,j-1],f[k1,j]);
55     for j:=1 to n do
56       f[k2,j]:=f[k2,j]+abs(p[i]-a[j]);
57   end;
58   ans:=2147483647;
59   for i:=1 to n do
60     ans:=min(f[k2,i],ans);
61   writeln(ans);
62 end.
View Code

 

posted on 2013-12-20 23:36  acphile  阅读(217)  评论(0编辑  收藏  举报