pku3659 Cell Phone Network
给定一棵树,要求对于每一个节点,要么自己放联络器,要么儿子放联络器,要么父亲放联络器,求让所有点满足条件的最少联络器数。
一道经典的看守皇宫问题,用DP解决。
f[0,now]表示在now节点放联络器的以now为根的子树的最小代价
f[1,now]表示now节点不放联络器,被他的儿子联络的以now为根的子树的最小代价
f[2,now]表示now节点不放联络器,被他的父亲联络的以now为根的子树的最小代价
注意树的形态开始并不确定,需要DFS一次来建树。
状态的转移在程序里很清楚,输出答案是min{f[0,1],f[1,1]}(我以1为根节点重建的树),因为根节点不可能再有父亲了,f[2,1]没有意义。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program pku3659(input,output);
2 type
3 node = ^link;
4 link = record
5 goal : longint;
6 next : node;
7 end;
8 var
9 l : array[0..10001] of node;
10 v : array[0..10001] of boolean;
11 tree : array[0..10001] of node;
12 f : array[0..2,0..10001] of longint;
13 n : longint;
14 procedure add(xx,yy: longint );
15 var
16 tt : node;
17 begin
18 new(tt);
19 tt^.goal:=yy;
20 tt^.next:=l[xx];
21 l[xx]:=tt;
22 end; { add }
23 procedure init;
24 var
25 i,x,y : longint;
26 begin
27 readln(n);
28 for i:=1 to n do
29 begin
30 tree[i]:=nil;
31 l[i]:=nil;
32 end;
33 for i:=1 to n-1 do
34 begin
35 readln(x,y);
36 add(x,y);
37 add(y,x);
38 end;
39 fillchar(f,sizeof(f),63);
40 fillchar(v,sizeof(v),false);
41 v[1]:=true;
42 f[2,0]:=0;
43 end; { init }
44 procedure dfs(now : longint );
45 var
46 t,tt : node;
47 begin
48 t:=l[now];
49 while t<>nil do
50 begin
51 if not v[t^.goal] then
52 begin
53 v[t^.goal]:=true;
54 new(tt);
55 tt^.goal:=t^.goal;
56 tt^.next:=tree[now];
57 tree[now]:=tt;
58 dfs(t^.goal);
59 end;
60 t:=t^.next;
61 end;
62 end; { dfs }
63 function min(aa,bb : longint ):longint;
64 begin
65 if aa<bb then
66 exit(aa);
67 exit(bb);
68 end; { min }
69 procedure dp(now : longint );
70 var
71 t : node;
72 sum,minw : longint;
73 flag : boolean;
74 begin
75 if now=0 then
76 exit;
77 if tree[now]=nil then
78 begin
79 f[0,now]:=1;
80 f[1,now]:=maxlongint>>2;
81 f[2,now]:=0;
82 exit;
83 end;
84 t:=tree[now];
85 while t<>nil do
86 begin
87 dp(t^.goal);
88 t:=t^.next;
89 end;
90 sum:=0;
91 t:=tree[now];
92 while t<>nil do
93 begin
94 sum:=sum+min(f[0,t^.goal],min(f[1,t^.goal],f[2,t^.goal]));
95 t:=t^.next;
96 end;
97 f[0,now]:=sum+1;
98 sum:=0;
99 t:=tree[now];
100 while t<>nil do
101 begin
102 sum:=sum+min(f[0,t^.goal],f[1,t^.goal]);
103 t:=t^.next;
104 end;
105 f[2,now]:=sum;
106 flag:=false;
107 sum:=0;
108 t:=tree[now];
109 while t<>nil do
110 begin
111 if f[1,t^.goal]>=f[0,t^.goal] then
112 begin
113 sum:=sum+f[0,t^.goal];
114 flag:=true;
115 end
116 else
117 sum:=sum+f[1,t^.goal];
118 t:=t^.next;
119 end;
120 if flag then
121 f[1,now]:=sum
122 else
123 begin
124 minw:=maxlongint>>1;
125 t:=tree[now];
126 while t<>nil do
127 begin
128 if f[0,t^.goal]-f[1,t^.goal]<minw then
129 minw:=f[0,t^.goal]-f[1,t^.goal];
130 t:=t^.next;
131 end;
132 sum:=sum+minw;
133 f[1,now]:=sum;
134 end;
135 end; { dp }
136 procedure print;
137 begin
138 writeln(min(f[0,1],f[1,1]));
139 end; { print }
140 begin
141 init;
142 dfs(1);
143 dp(1);
144 print;
145 end.