浙大PAT 1021. Deepest Root (25)

1021. Deepest Root (25)

时间限制
1500 ms
内存限制
32000 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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
并查集的相关资料前面已经有介绍了,所以用并查集判断是否是树很简单,然后就是最长根的查找,这里用的是dfs,其实bfs更容易解该问题。
查找最长根的时候,首先从一点进行深搜,把其中距离最远的点记录下来(可访问到所有顶点,因为已经保证是树),然后从这些最远点中任选一点再进行深度搜索,这个时候的所有最远点都是最长根,关键是第一遍dfs保存的最远点也是最长根,这个地方最难理解了,首先,若第一遍dfs后的最远根不在从1开始的同一条支路上(他们的最近公共祖先是1),这是这些点必定都会是将来的最长根这很明显,若第一遍dfs后的最远根在从1开始的同一条支路上(他们的最近公共祖先不是1记为f),则第二遍dfs时的最长根所在的dfs遍历序列必过f,所以此时的情况又可将f点看做第一种情况中的1节点类似。综上第一次与第二次dfs的合集才是最终结果

#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
#include <set>

using namespace std;

const int maxx = 10001;

map<int,vector<int> > tree;
set<int> res;
set<int> tres;
int pre[maxx],cnt,maxn = -1;
int visit[maxx];

void dfs(int p,int step){
	if(step>maxn){
		res.clear();
		res.insert(p);
		maxn = step;
	}else if(step==maxn){
		res.insert(p);
	}

	vector<int>::iterator ite = tree[p].begin();
	for(;ite!=tree[p].end();++ite){
		if(visit[*ite]!=1){
			visit[*ite] = 1;
			dfs(*ite,step+1);
			visit[*ite] = 0;
		}
	}
}

void init(int n){
	int i;

	for(i=1;i<=n;++i){
		pre[i]=i;
		visit[i]=0;
	}
}

int root(int x){
	if(x!=pre[x]){
		pre[x] = root(pre[x]);
	}
	return pre[x];
}

void merge(int x,int y){
	int fa = root(x);
	int fb = root(y);
	if(fa!=fb){
		pre[fa] = fb;
		--cnt;
	}
}

int main(){
	int n,i,a,b;
	set<int>::iterator ite;
	scanf("%d",&n);
	cnt = n-1;

	init(n);

	for(i=1;i<n;++i){
		scanf("%d %d",&a,&b);
		tree[a].push_back(b);
		tree[b].push_back(a);
		merge(a,b);
	}

	if(cnt!=0){
		printf("Error: %d components\n",1+cnt);
		return 0;
	}

	visit[1] = 1;
	dfs(1,1);
	visit[1] = 0;//因为已经是树,所以不会再有环了,所以所有dfs后都恢复该点的可访问性很重要

	ite = res.begin();
	for(;ite!=res.end();++ite){
		tres.insert(*ite);
	}

	
	int point = (*res.begin());
	visit[point] = 1;
	dfs(point,1);
	visit[point] = 0;

	ite = res.begin();
	for(;ite!=res.end();++ite){
		tres.insert(*ite);
	}

	ite = tres.begin();
	for(;ite!=tres.end();++ite){
		printf("%d\n",*ite);
	}

	return 0;
}


你可能感兴趣的:(C++,c,DFS,并查集,pat)