Description
给出一个树形图(“tree-shaped” network),有N(1 <= N <= 10,000)个顶点。如果删除树上某一个顶点,整棵树就会分割成若干个部分。显然,每个部分内部仍保持连通性。
现在问:删除哪个点,使得分割开的每个连通子图中点的数量不超过N/2。如果有很多这样的点,就按升序输出。
Input
第1行:1个整数N,表示顶点数。顶点编号1~N
第2..N行:每行2个整数X和Y,表示顶点X与Y之间有一条边
Output
若干行,每行1个整数,表示一个符合条件的顶点的编号。如果没有顶点符合条件,则仅在第1行上输出”NONE”
分析
首先读入数据,并构图。
然后就是标准的DFS。返回以i为根的子树的结点总数。
当删除结点i时,整棵树被分成了i的父结点以上的部分,以及i以下的每棵子树部分。根据题意,每个部分的结点个数都不能超过n/2。
每棵子树返回的结点数可以在递归时得到,每枚举一个子结点时,判断一下返回值就行。
对于i的父结点以上的部分,其实也很简单,就是总结点数减去i为根的总结点数。
当i符合条件后,把它压入一个数组ans。递归结束后,对ans排序、输出。
代码
const
maxn=20000;
maxe=50000;
type
arr=record
w:boolean;
x,y:longint;
next:longint;
end;
var
edge:array[1..maxe] of arr;
ls:array[1..maxn] of longint;
number:array[1..maxn] of longint;
n,m:longint;
procedure add(x,y:longint);
begin
m:=m+1;
edge[m].x:=x;
edge[m].y:=y;
edge[m].next:=ls[x];
ls[x]:=m;
end;
procedure init;
var
i,j,k:longint;
begin
readln(n);
for i:=1 to n-1 do
begin
readln(j,k);
add(j,k);
add(k,j);
end;
end;
function tree(x,root:longint):longint;
var
i,j,k:longint;
begin
i:=ls[root];
while i<>0 do
begin
if edge[i].y=x
then
begin
edge[i].w:=true;
i:=edge[i].next;
continue;
end;
number[root]:=tree(root,edge[i].y)+number[root];
i:=edge[i].next;
end;
inc(number[root]);
tree:=number[root];
end;
procedure main;
var
i,j,k:longint;
flag,flag2:boolean;
begin
init;
tree(0,1);
flag2:=false;
for i:=1 to n do
begin
j:=ls[i];
flag:=false;
while j<>0 do
with edge[j] do
begin
if w
then
begin
j:=next;
continue;
end;
if number[y]>n div 2
then begin
flag:=true;
break;
end;
j:=next;
end;
if number[1]-number[i]>n div 2
then flag:=true;
if not flag
then begin
writeln(i);
flag2:=true;
end;
end;
if not flag2
then write('NONE');
end;
begin
main;
end.