1. 程式人生 > >POJ 1655 Balancing Act 樹的重心

POJ 1655 Balancing Act 樹的重心

Balancing Act

Time Limit: 1000MS

Memory Limit: 65536K

Total Submissions: 16866

Accepted: 7130

Description

Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the largest tree in the forest T created by deleting that node from T.  For example, consider the tree: 

http://poj.org/images/1655_1.jpg

Deleting node 4 yields two trees whose member nodes are {5} and {1,2,3,6,7}. The larger of these two trees has five nodes, thus the balance of node 4 is five. Deleting node 1 yields a forest of three trees of equal size: {2,6}, {3,7}, and {4,5}. Each of these trees has two nodes, so the balance of node 1 is two.  For each input tree, calculate the node that has the minimum balance. If multiple nodes have equal balance, output the one with the lowest number. 

Input

The first line of input contains a single integer t (1 <= t <= 20), the number of test cases. The first line of each test case contains an integer N (1 <= N <= 20,000), the number of congruence. The next N-1 lines each contains two space-separated node numbers that are the endpoints of an edge in the tree. No edge will be listed twice, and all edges will be listed.

Output

For each test case, print a line containing two integers, the number of the node with minimum balance and the balance of that node.

Sample Input

1
7
2 6
1 2
1 4
4 5
3 7
3 1

Sample Output

1 2

Source

演算法分析:

 num[i] 儲存自己所有除祖先以外所有子樹的節點總和,dp[i]儲存所有子樹中最大的子樹的節點數,

程式碼實現:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int N=20010;
struct node
{
	int v;///終端點
    int next;///下一條同樣起點的邊號
    int w;///權值
}edge[N*2];///無向邊,2倍
int head[N];///head[u]=i表示以u為起點的所有邊中的第一條邊是 i號邊
int tot;  ///總邊數
void add(int u,int v)
{
	edge[tot].v=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n;
int dp[N],num[N];
void dfs(int u,int fa)   ///求出每個節點子樹下的最大距離和次大距離
{
	num[u]=1;
	 for(int i=head[u];i!=-1;i=edge[i].next)
	 {
	 	int v= edge[i].v;
	    if(fa==v) continue;
		dfs(v,u);
	    dp[u]=max(dp[u],num[v]);
	    num[u]+=num[v];
	 }
	 dp[u]=max(dp[u],n-num[u]);
}

int main()
{
  
  int t;
  scanf("%d",&t);
  while(t--)
  {
  	scanf("%d",&n);
  	memset(head,-1,sizeof(head));
    memset(dp,-1,sizeof(dp));
  	tot=0;
  	
  	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
  	dfs(1,-1);
  	
	int point;      
	int ans = 1e9;   
	for(int i = 1; i <= n; i ++)   
	{          
		if(dp[i] < ans)            
  	  {       
  	  	 point = i;     
		 ans = dp[i];        
	  }     
	}      
	printf("%d %d\n",point, ans);

  }
  
  return 0;
}