Pat(Advanced Level)Practice-1021(Deepest Root)

Pat(Advanced Level)Practice--1021(Deepest Root)

Pat1021代码

题目描述:

A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (<=10000) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N-1 lines follow, each describes an edge by given the two adjacent nodes' numbers.

Output Specification:

For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print "Error: K components" where K is the number of connected components in the graph.

Sample Input 1:
5
1 2
1 3
1 4
2 5
Sample Output 1:
3
4
5
Sample Input 2:
5
1 3
1 4
2 5
3 4
Sample Output 2:
Error: 2 components

AC代码:
题目是要判断图是否都连接构成树,求使树高最大的所有的根,实际上求图上两点间最大距离。
参考网上程序,发现树的最长路径其实有个很方便的求法。任取一个点x,求出距离x最远的一个点y,然后求出距离y最远的一个点z。y到z就是一条最长路径。他是先用并查集判断共有几个部分,再bfs求距离,先任取一点开始bfs,得到最远的叶节点,以此叶节点再bfs可得。
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#define MAX 10005

using namespace std;

int dis[MAX];
vector<int> adj[MAX];
int parent[MAX];
int n;

int Find(int x)
{
	int p=x;
	while(p!=parent[p])
		p=parent[p];
	return p;
}

void Union(int x,int y)
{
	int fx,fy;
	fx=Find(x);
	fy=Find(y);
	if(fx!=fy)
		parent[fx]=fy;
}

int BFS(int start)
{
	for(int i=1;i<=n;i++)
		dis[i]=-1;
	queue<int> q;
	q.push(start);
	dis[start]=0;
	int maxdis=0;
	while(!q.empty())
	{
		int cur=q.front();
		for(int i=0;i<adj[cur].size();i++)
		{
			int temp=adj[cur][i];
			if(dis[temp]<0)
			{
				q.push(temp);
				dis[temp]=dis[cur]+1;
				if(dis[temp]>maxdis)
					maxdis=dis[temp];
			}
		}
		q.pop();
	}
	return maxdis;
}

int main(int argc,char *argv[])
{
	int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		parent[i]=i;
	for(i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		adj[x].push_back(y);
		adj[y].push_back(x);
		Union(x,y);
	}
	int count=0;
	for(i=1;i<=n;i++)
		if(parent[i]==i)
			count++;
	if(count>1)
		printf("Error: %d components\n",count);
	else
	{
		map<int,int> m;
		int max=BFS(1);
		int index,first=1;
		for(i=1;i<=n;i++)
		{
			if(dis[i]==max&&first)
			{
				index=i;
				m[i]++;
				first=0;
			}
			else if(dis[i]==max)
				m[i]++;
		}
		max=BFS(index);
		dis[i]=max;
		for(i=1;i<=n;i++)
			if(dis[i]==max)
				m[i]++;
		map<int,int>::iterator it;
		for(it=m.begin();it!=m.end();it++)
			printf("%d\n",it->first);
	}

	return 0;
}

其实,这题比较难理解的是第一次BFS的最远点也是deepest root;下面简单的证明一下:
假设从A点开始BFS找到一个最远点C,树中其中一个deep root是从X到Z,那么就有
     A---------------------->C
X-------------------------->Z
因为这是一棵树那么必然AC与XZ有交点,否则就不是一个树了,于是
     A-------B------------->C 
X-----------B------------->Z ( 就这样吧实在没法画图)
假设AC与XZ相交于B点,那么必然有BC等于BZ;
如果两者不相等,便不满足1,C是距离A最远的点;2,XZ距离在整棵树中最远;
因此C也是deepest root,也就是说第一次BFS得到的最远点也是deepest root,所以结果就是第一次BFS和
第二次BFS的并集;
(PS:这题用两次BFS与两次DFS都可以,因为求的是最远距离)