给定起点和要经过的点,求最短路径
我发现,关于路径的treedp,设计的关键在于每个节点的状态怎么表示
对于这道题,有一种常见的方法是令f[i,1]表示经过这个点且还要回来的路径,
f[i,0]表示留在以i为根的子树的某个节点上不回到i的最短路径
然后方程就很好设计了,具体见程序

 1 type node=record
 2        next,cost,point:longint;
 3      end;
 4 
 5 var edge:array[0..100010] of node;
 6     need,v:array[0..50010] of boolean;
 7     p:array[0..50010] of longint;
 8     f:array[0..50010,0..1] of longint;
 9     len,n,m,root,x,y,z,i:longint;
10 
11 procedure add(x,y,z:longint);
12   begin
13     inc(len);
14     edge[len].point:=y;
15     edge[len].cost:=z;
16     edge[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 treedp(x:longint);
26   var i,y:longint;
27   begin
28     i:=p[x];
29     v[x]:=true;
30     while i<>-1 do
31     begin
32       y:=edge[i].point;
33       if not v[y] then
34       begin
35         treedp(y);
36         if need[y] then
37         begin
38           f[x,0]:=min(f[y,0]+f[x,1]+edge[i].cost,f[x,0]+edge[i].cost*2+f[y,1]); 
39           //在停在之前的最优点和停在当前点为根的子树上这两种情况选择一个较优的
40           f[x,1]:=f[x,1]+f[y,1]+edge[i].cost*2;  //无需多说
41           need[x]:=true;
42         end;
43       end;
44       i:=edge[i].next;
45     end;
46   end;
47 
48 begin
49   readln(n,root);
50   fillchar(p,sizeof(p),255);
51   for i:=1 to n-1 do
52   begin
53     readln(x,y,z);
54     add(x,y,z);
55     add(y,x,z);
56   end;
57   readln(m);
58   for i:=1 to m do
59   begin
60     read(x);
61     need[x]:=true;
62   end;
63   treedp(root);
64   writeln(f[root,0]);
65 end.
66 
67  
View Code

 

posted on 2014-09-11 21:25  acphile  阅读(190)  评论(0编辑  收藏  举报