PKU 1655-Balancing Act
問題概要
ノード数がN(<=20000)の木がある.
ある一つのノードを取り外すことで木を切断した時に残る複数の木の最大ノード数をバランスという.
バランスの最小値を求めよ
解法
木の根を入次数が1の頂点から適当に決める.
そうすると,それよりも深い部分の頂点の個数をO(E)で計算することが出来,それにより最終的な計算量もO(E)となる.
実装(C++)
#include <cstdio> #include <iostream> #include <vector> #include <algorithm> using namespace std; int TCASE; #define REP(i,x)for(int i=0;i<(int)x;i++) vector<int> G[20000]; bool ac[20000]; int cnt[20000]; int ans=99999999; int ansno=-1; int dfs(int now,int back=-1){ if(cnt[now]>0)return cnt[now]; cnt[now]=1; REP(i,G[now].size()){ if(G[now][i]!=back){ cnt[now]+=dfs(G[now][i],now); } } return cnt[now]; } int N; void solve(int now,int back=-1){ //ここで消してみる int tans=N-cnt[now]; REP(i,G[now].size()){ if(G[now][i]!=back){ tans=max(tans,cnt[G[now][i]]); } } if(ans>tans){ ans=tans; ansno=now; }else if(ans==tans&&ansno>now){ ansno=now; } REP(i,G[now].size()){ if(G[now][i]!=back){ solve(G[now][i],now); } } } int main() { scanf("%d",&TCASE); while(TCASE--){ scanf("%d",&N); REP(i,N)G[i].clear(); REP(i,N-1){ int a,b; scanf("%d%d",&a,&b); b--;a--; G[a].push_back(b); G[b].push_back(a); } int root=-1; REP(i,N){ if(G[i].size()==1){ root=i;break; } } ansno=-1; ans=99999999; fill(ac,ac+N,0); fill(cnt,cnt+N,0); dfs(root); solve(root); cout<<ansno+1<<" "<<ans<<endl; } return 0; }