珠宝(GEMS)
给一棵n 个结点的树,给每个点安排一个正整数编号,使得相邻点具有不同的编号,编号的
总和尽量小。
输入文件:
第一行:n(n<=50,000)
以下n-1 行,每行两个数u,v(1<=u,v<=n),表示u和v 有一条边
输出文件:
仅一行,为最小编号和
SAMPLE INPUT
8
1 2
1 3
1 4
1 5
5 6
5 7
5 8
SAMPLE OUTPUT
11
================
树形DP
=======================
type
pnode=^node;
node=record
x:longint;
next:pnode;
end;
var
n:longint;
tree:array[1..50000]of pnode;
//f_son:array[1..50000]of pnode;
f_n,f_flag:array[1..50000,1..2]of longint;
f:array[1..50000,1..50]of longint;
f_bo:array[1..50000]of boolean;
procedure init;
begin
assign(input,'gems.in');
assign(output,'gems.out');
reset(input); rewrite(output);
end;
procedure terminate;
begin
close(input); close(output);
halt;
end;
procedure insert(a,b:longint);
var
p:pnode;
begin
new(p);
p^.x:=b;
p^.next:=tree[a];
tree[a]:=p;
end;
procedure dfs(t:longint);
var
p:pnode;
i,j:longint;
now:longint;
begin
f_bo[t]:=false;
p:=tree[t];
while p<>nil do
begin
if f_bo[p^.x] then
begin
dfs(p^.x);
end;
p:=p^.next;
end;
for i:=1 to 50 do //枚举根节点的分数..
begin
now:=0;
p:=tree[t];
while p<>nil do
begin
if f_flag[p^.x,1]<>0 then
begin
if f_flag[p^.x,1]=i then inc(now,f_n[p^.x,2])
else inc(now,f_n[p^.x,1]);
end;
p:=p^.next;
end;
if now+i<f_n[t,1] then
begin
f_n[t,2]:=f_n[t,1]; f_flag[t,2]:=f_flag[t,1];
f_n[t,1]:=now+i; f_flag[t,1]:=i;
continue;
end;
if now+i<f_n[t,2] then
begin
f_n[t,2]:=now+i; f_flag[t,2]:=i;
end; {更新}
end;
end;
procedure main;
var
i:longint;
u,v:longint;
begin
readln(n);
for i:=1 to n do
begin
tree[i]:=nil;
end;
for i:=1 to n-1 do
begin
readln(u,v);
insert(u,v);
insert(v,u);
end;
fillchar(f_n,sizeof(f_n),$7);
fillchar(f_flag,sizeof(f_flag),0);
fillchar(f_bo,sizeof(f_bo),true);
dfs(1);
writeln(f_n[1,1]);
end;
begin
init;
main;
terminate;
end.