给定起点和要经过的点,求最短路径
我发现,关于路径的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