I and OI
Past...

题意:给定一棵树,问删除哪个点,使余下的各个子树结点个数的最大值最小.

分析:先DFS一次,求出以每个节点为根的子树的节点个数s[i].

设f[i]表示去掉i后,余下的各个子树结点个数的最大值.

f[i]=max(n-s[i],max{s[j]}). (j为i的儿子).

这样再DFS一次,求出max{f[i]}即为答案.

code:

type  edge=record
      v,n:longint;
end;
const maxn=20001;
      oo=100000000;
var   e:array[0..maxn*2] of edge;
      h,s,f:array[0..maxn] of longint;
      vis:array[0..maxn] of boolean;
      dnum,d,n,i,u,v,cnt,min,mi:longint;

      procedure swap(var a,b:longint);
      var   tmp:longint;
      begin
            tmp:=a; a:=b; b:=tmp;
      end;

      function max(a,b:longint):longint;
      begin
            if a>b then exit(a); exit(b);
      end;

      procedure add(u,v:longint);
      begin
            inc(cnt);
            e[cnt].v:=v;
            e[cnt].n:=h[u];
            h[u]:=cnt;
      end;

      procedure dfs(u:longint);
      var   v,p:longint;
      begin
            vis[u]:=true;
            p:=h[u];
            while p<>0 do
            begin
                  v:=e[p].v;
                  if not vis[v] then
                  begin
                        dfs(v);
                        inc(s[u],s[v]);
                  end;
                  p:=e[p].n;
            end;
            inc(s[u]);
      end;

      procedure dp(u:longint);
      var   v,p,tmp:longint;
      begin
            vis[u]:=true;
            tmp:=n-s[u];
            p:=h[u];
            while p<>0 do
            begin
                  v:=e[p].v;
                  if not vis[v] then
                  begin
                        dp(v);
                        tmp:=max(tmp,s[v]);
                  end;
                  p:=e[p].n;
            end;
            f[u]:=tmp;
      end;

begin
      readln(dnum);
      for d:=1 to dnum do
      begin
            fillchar(h,sizeof(h),0);
            fillchar(f,sizeof(f),0);
            fillchar(s,sizeof(s),0);
            cnt:=0;
            readln(n);
            for i:=1 to n-1 do
            begin
                  readln(u,v);
                  add(u,v);
                  add(v,u);
            end;
            fillchar(vis,sizeof(vis),0);
            dfs(1);
            fillchar(vis,sizeof(vis),0);
            dp(1);
            min:=oo; mi:=0;
            for i:=1 to n do
               if f[i]<min then
               begin
                     min:=f[i];
                     mi:=i;
               end;
            writeln(mi,' ',min);
      end;
end.

posted on 2011-08-10 15:49  exponent  阅读(867)  评论(0编辑  收藏  举报