参考论文《对一类动态规划问题的研究》

《多角度思考创造性思维——运用树型动态规划解题的思路和方法探析》

这类动态规划的特点就是当前的决策会影响未来“行动”的费用,而我们并不能记录每个的所有决策

这时候我们就考虑在当前状态对未来状态预估,从而提前计算当前决策对未来影响的费用

下面的几道题目都很好,并且都能在这两篇论文中找到详细的题解,这里就贴代码不再赘述了

bzoj1812

不错的树dp,处理x为根子树的时候,我们预估x的某个祖先有伐木场时子树内的运费

详见《多角度思考创造性思维——运用树型动态规划解题的思路和方法探析》

  1 const inf=2147483647;
  2 type node=record
  3        po,next,num:longint;
  4      end;
  5 
  6 var e:array[0..210] of node;
  7     w,fa,p,d,g:array[0..110] of longint;
  8     f:array[0..110,0..110,0..110] of longint;
  9     i,j,k,len,x,y,n,m:longint;
 10 
 11 procedure add(x,y,z:longint);
 12   begin
 13     inc(len);
 14     e[len].po:=y;
 15     e[len].num:=z;
 16     e[len].next:=p[x];
 17     p[x]:=len;
 18   end;
 19 
 20 function min(a,b:longint):longint;
 21   begin
 22     if a>b then exit(b) else exit(a);
 23   end;
 24 
 25 procedure dfs(x:longint);
 26   var i,y,z,mi:longint;
 27   begin
 28     if p[x]=0 then
 29     begin
 30       i:=fa[x];
 31       while i>-1 do
 32       begin
 33         f[x,i,0]:=(d[x]-d[i])*w[x];
 34         i:=fa[i];
 35       end;
 36       f[x,x,1]:=0;
 37       exit;
 38     end;
 39     i:=p[x];
 40     while i<>0 do
 41     begin
 42       y:=e[i].po;
 43       d[y]:=d[x]+e[i].num;
 44       dfs(y);
 45       i:=e[i].next;
 46     end;
 47     i:=p[x];
 48     while i<>0 do
 49     begin
 50       y:=e[i].po;
 51       z:=x;
 52       while z>-1 do
 53       begin
 54         for j:=m downto 0 do
 55         begin
 56           mi:=inf;
 57           for k:=0 to j do
 58             mi:=min(mi,f[x,z,k]+f[y,z,j-k]);
 59           f[x,z,j]:=mi;
 60         end;
 61         z:=fa[z];
 62       end;
 63       i:=e[i].next;
 64     end;
 65     z:=fa[x];
 66     while z>-1 do
 67     begin
 68       for i:=0 to m do
 69         if f[x,z,i]<inf then f[x,z,i]:=f[x,z,i]+(d[x]-d[z])*w[x];
 70       z:=fa[z];
 71     end;
 72     fillchar(g,sizeof(g),0);
 73     i:=p[x];
 74     while i<>0 do
 75     begin
 76       y:=e[i].po;
 77       for j:=m downto 0 do
 78       begin
 79         mi:=inf;
 80         for k:=1 to j do
 81           mi:=min(mi,g[k]+f[y,x,j-k]);
 82         g[j]:=mi;
 83       end;
 84       i:=e[i].next;
 85     end;
 86     z:=x;
 87     while z>-1 do
 88     begin
 89       for i:=0 to m do
 90         f[x,z,i]:=min(f[x,z,i],g[i]);
 91       z:=fa[z];
 92     end;
 93   end;
 94 
 95 begin
 96   readln(n,m);
 97   for i:=1 to n do
 98   begin
 99     readln(w[i],fa[i],y);
100     add(fa[i],i,y);
101   end;
102   fa[0]:=-1;
103   dfs(0);
104   writeln(f[0,0,m]);
105 end.
View Code

bzoj1495

非常好的树dp,处理x为根子树的时候,预估x的祖先AB付费方式的大小情况从而计算影响

具体请见《多角度思考创造性思维——运用树型动态规划解题的思路和方法探析》

其中转换计算方式,对状态的压缩以及复杂度的分析都非常有价值,建议认真研究

 1 const inf=1000000007;
 2 var a,f:array[0..2050,0..2050] of longint;
 3     d,b,c:array[0..2050] of longint;
 4     n,m,x,y,i,j,k,p,l,r,ans:longint;
 5 
 6 function min(a,b:longint):longint;
 7   begin
 8     if a>b then exit(b) else exit(a);
 9   end;
10 
11 function lca(a,b:longint):longint;
12   begin
13     while a<>b do
14     begin
15       if a>b then a:=a div 2
16       else b:=b div 2;
17     end;
18     exit(a);
19   end;
20 
21 begin
22   readln(n);
23   m:=1 shl n;
24   for i:=1 to m do
25     read(b[i]);
26   for i:=1 to m do
27     read(c[i]);
28   for i:=2 to m*2-1 do
29     d[i]:=d[i div 2]+1;
30   readln;
31   for i:=1 to m-1 do
32   begin
33     for j:=i+1 to m do
34     begin
35       read(y);
36       x:=d[lca(i+m-1,j+m-1)];
37       inc(a[i,x],y);
38       inc(a[j,x],y);
39     end;
40     readln;
41   end;
42   for i:=m to m*2-1 do
43   begin
44     x:=i-m+1;
45     for j:=0 to m-1 do
46     begin
47       f[i,j shl 1+b[x]]:=c[x];
48       for k:=0 to n-1 do
49       begin
50         if (j and (1 shl k)>0) then y:=1 else y:=0;
51         inc(f[i,j shl 1+1-y],a[x,k]);
52       end;
53     end;
54   end;
55   for i:=1 to m-1 do
56     for j:=0 to m*2-1 do
57       f[i,j]:=inf;
58 
59   for i:=m-1 downto 1 do
60     for j:=0 to 1 shl d[i]-1 do
61       for k:=0 to 1 shl (n-d[i]) do
62       begin
63         x:=j shl (n-d[i]+1) or k;
64         if k<1 shl (n-d[i])-k then y:=0 else y:=1;
65         for p:=0 to min(k,1 shl (n-d[i]-1)) do
66         begin
67           if k-p>1 shl (n-d[i]-1) then continue;
68           l:=((j+y*(1 shl d[i])) shl (n-d[i]))+p;
69           r:=((j+y*(1 shl d[i])) shl (n-d[i]))+(k-p);
70           f[i,x]:=min(f[i,x],f[i*2,l]+f[i*2+1,r]);
71         end;
72       end;
73 
74   ans:=f[1,0];
75   for i:=1 to m*2-1 do
76     ans:=min(ans,f[1,i]);
77 
78   writeln(ans);
79 end.
View Code

bzoj1065

也是非常好的树dp,可以看《对一类动态规划问题的研究》,讲解的很详细

在做树dp的时候预估当前子树的跟x距1的深度所带来的影响(因为x的祖先的后继可能被修改连到1)

 1 var f:array[0..70,0..70,0..70] of double;
 2     g,c,b:array[0..70] of double;
 3     p:array[0..70] of longint;
 4     j,tmp,i,n,m,len:longint;
 5     ans:double;
 6 
 7 function max(a,b:double):double;
 8   begin
 9     if a>b then exit(a) else exit(b);
10   end;
11 
12 function min(a,b:longint):longint;
13   begin
14     if a>b then exit(b) else exit(a);
15   end;
16 
17 procedure dfs(x,d:longint);
18   var i,j,k,l:longint;
19   begin
20     for i:=2 to n do
21       if p[i]=x then dfs(i,d+1);
22     for l:=min(2,d) to d do
23     begin
24       for i:=2 to n do
25         if p[i]=x then
26         begin
27           for j:=m downto 0 do //树上背包注意转移顺序
28             for k:=j downto 0 do
29               f[x,j,l]:=max(f[x,j,l],f[x,k,l]+max(f[i,j-k,l+1],f[i,j-k,1]));
30         end;
31       for j:=0 to m do
32         f[x,j,l]:=f[x,j,l]+c[x]*b[l];
33     end;
34     if d>1 then
35     begin
36       fillchar(g,sizeof(g),0);
37       for i:=2 to n do
38         if p[i]=x then
39         begin
40           for j:=m downto 0 do
41             for k:=j downto 0 do
42               g[j]:=max(g[j],g[k]+max(f[i,j-k,1],f[i,j-k,2]));
43         end;
44       for j:=1 to m do
45         f[x,j,1]:=g[j-1]+c[x]*b[1];
46     end;
47   end;
48 
49 function dp:double;
50   var i,j,k:longint;
51   begin
52     fillchar(g,sizeof(g),0);
53     for i:=2 to n do
54       if p[i]=1 then
55       begin
56         for j:=m downto 0 do
57           for k:=j downto 0 do
58             g[j]:=max(g[j],g[k]+f[i,j-k,1]);
59       end;
60     dp:=0;
61     for i:=0 to m-1 do
62       dp:=max(dp,g[i]);
63     if tmp=1 then dp:=max(dp,g[m]);  //原来后继就是1就不用修改
64   end;
65 
66 begin
67   readln(n,m,b[1]);
68   for i:=2 to n do
69     b[i]:=b[i-1]*b[1];
70   for i:=1 to n do
71     read(p[i]);
72   for i:=1 to n do
73     read(c[i]);
74   len:=2;
75   i:=p[1];
76   while i<>1 do  //穷举环长
77   begin
78     fillchar(f,sizeof(f),0);
79     tmp:=p[i];
80     p[i]:=1;
81     for j:=2 to n do
82       if p[j]=1 then dfs(j,1);
83     ans:=max(ans,(dp+c[1])/(1-b[len]));
84     p[i]:=tmp;
85     i:=p[i];
86     inc(len);
87   end;
88   writeln(ans:0:2);
89 end.
View Code

bzoj2037

相对简单,这题不用新开状态,直接在当前状态加上对未来的影响即可

详见《对一类动态规划问题的研究》

 1 var f:array[0..1010,0..1010,1..2] of longint;
 2     w:array[0..1010,0..1010] of longint;
 3     s,a,b,v:array[0..1010] of longint;
 4     i,j,l,n,x0:longint;
 5 
 6 procedure swap(var a,b:longint);
 7   var c:longint;
 8   begin
 9     c:=a;
10     a:=b;
11     b:=c;
12   end;
13 
14 procedure sort(l,r:longint);
15   var i,j,x:longint;
16   begin
17     i:=l;
18     j:=r;
19     x:=a[(l+r) shr 1];
20     repeat
21       while a[i]<x do inc(i);
22       while x<a[j] do dec(j);
23       if not(i>j) then
24       begin
25         swap(a[i],a[j]);
26         swap(b[i],b[j]);
27         swap(v[i],v[j]);
28         inc(i);
29         dec(j);
30       end;
31     until i>j;
32     if l<j then sort(l,j);
33     if i<r then sort(i,r);
34   end;
35 
36 function max(a,b:longint):longint;
37   begin
38     if a>b then exit(a) else exit(b);
39   end;
40 
41 function cost(a,b:longint):longint;
42   begin
43     exit(a*b);
44   end;
45 
46 begin
47   readln(n,x0);
48   for i:=1 to n do
49     read(a[i]);
50   for i:=1 to n do
51     read(b[i]);
52   for i:=1 to n do
53     read(v[i]);
54   sort(1,n);
55   for i:=1 to n do
56     s[i]:=s[i-1]+v[i];
57   for i:=1 to n do
58     for j:=i to n do
59       w[i,j]:=s[n]-(s[j]-s[i-1]);
60   for i:=1 to n do
61   begin
62     f[i,i,1]:=b[i]-cost(abs(a[i]-x0),s[n]);
63     f[i,i,2]:=f[i,i,1];
64   end;
65   for l:=2 to n do
66     for i:=1 to n-l+1 do
67     begin
68       j:=i+l-1;
69       f[i,j,1]:=b[i]+max(f[i+1,j,1]-cost(a[i+1]-a[i],w[i+1,j]),f[i+1,j,2]-cost(a[j]-a[i],w[i+1,j]));
70       f[i,j,2]:=b[j]+max(f[i,j-1,2]-cost(a[j]-a[j-1],w[i,j-1]),f[i,j-1,1]-cost(a[j]-a[i],w[i,j-1]));
71     end;
72   writeln(max(f[1,n,1],f[1,n,2])/1000:0:3);
73 end.
View Code

poj1390

区间dp,对于消去区间[i,j],我们预估后面会连接k个和区域j同色的方块来计算分数

详见《对一类动态规划问题的研究》

 1 var f:array[0..201,0..201,0..201] of longint;
 2     wh:array[0..201,0..201] of longint;
 3     len,color,s,loc,a,maxl,sc:array[0..201] of longint;
 4     l,w,i,j,k,r,t,n,q,p:longint;
 5 
 6 function max(a,b:longint):longint;
 7    begin
 8      if a>b then exit(a) else exit(b);
 9    end;
10 
11 begin
12   readln(t);
13   for w:=1 to t do
14   begin
15     readln(r);
16     n:=0;
17     fillchar(s,sizeof(s),0);
18     fillchar(len,sizeof(len),0);
19     for i:=1 to r do
20     begin
21       read(a[i]);
22       if a[i]=a[i-1] then
23         inc(len[n])
24       else begin
25         inc(n);
26         inc(s[a[i]]);
27         loc[n]:=s[a[i]];
28         wh[a[i],s[a[i]]]:=n;
29         len[n]:=1;
30         color[n]:=a[i];
31       end;
32     end;
33     fillchar(sc,sizeof(sc),0);
34     for i:=n downto 1 do
35     begin
36       maxl[i]:=sc[color[i]];
37       inc(sc[color[i]],len[i]);
38     end;
39     fillchar(f,sizeof(f),0);
40     for i:=1 to n do
41       for k:=0 to maxl[i] do
42         f[i,i,k]:=sqr(len[i]+k);
43     for l:=1 to n-1 do
44       for i:=1 to n-l do
45       begin
46         j:=i+l;
47         for k:=0 to maxl[j] do
48         begin
49           f[i,j,k]:=f[i,j-1,0]+sqr(len[j]+k);
50           q:=loc[j]-1;
51           while q>0 do
52           begin
53             p:=wh[color[j],q];
54             if p<i then break;
55             f[i,j,k]:=max(f[i,j,k],f[i,p,k+len[j]]+f[p+1,j-1,0]);
56             dec(q);
57           end;
58         end;
59       end;
60     writeln('Case ',w,': ',f[1,n,0]);
61   end;
62 end.
View Code

 

posted on 2015-07-21 17:14  acphile  阅读(365)  评论(0编辑  收藏  举报