1021 Deepest Root (25 point(s))

1021 Deepest Root (25 point(s))

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 (≤10​4​​) 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

注意点:

1. 并查集求连通分支的方法;

2. 图的存储方法;

3. DFS求树的深度以及各结点所在的层次

思路:

先给出结论,一棵有N个结点的树,一定有N-1条边(离散数学中有证明)。因此,首先用并查集来计算连通分支数,如果不连通输出,否则说明这一定是一棵树,没有环。

下一个任务是确定以哪一个结点为根,树有最大的深度。采用遍历每一个结点的方法,暴力求解,问题转化为已知根节点求树的深度。用数组visit[]、level[]分别记录第i个结点是否已经被访问以及所在的层次,使用DFS搜索。

参考大神链接:https://blog.csdn.net/richenyunqi/article/details/79551890

图相关的题目在近几年PAT-A中越来越多,需要重视!

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
const int MAX = 1e4+7;
int Tree[MAX];
int findRoot(int x){//寻找根结点 
	if(Tree[x]==-1) return x;
	else{
		int temp = findRoot(Tree[x]);
		Tree[x] = temp;
		return temp;
	}
}
bool visit[MAX];
int maxLevel[MAX];//第i个结点作为根节点时,树的最大深度
int level[MAX];//当前根节点下,第i个结点的层次(深度) 
vector<int> graph[MAX];
void dfs(int v,int curRoot){//寻找以curRoot为根节点,从v开始的各个结点的层次 
	visit[v]=true;
	for(int i=0;i<graph[v].size();i++){//遍历每个邻接结点 
		int k = graph[v][i];//当前邻接结点 
		if(!visit[k]){
			level[k]=level[v]+1;
			maxLevel[curRoot]=max(level[k],maxLevel[curRoot]);//跟新最大树深度 
			dfs(k,curRoot); 
		}
	} 
}
int main(void){
	int n,a,b;cin>>n;
	memset(Tree,-1,sizeof(Tree));
	for(int i=1;i<=n-1;i++){
		cin>>a>>b;
		int na = findRoot(a);
		int nb = findRoot(b);
		if(na!=nb) Tree[na]=nb;
		graph[a].push_back(b);
		graph[b].push_back(a);
	}
	int bCnt=0;//计算连通分支数 
	for(int i=1;i<=n;i++){
		if(Tree[i]==-1) bCnt++;
	}
	if(bCnt>=2) cout<<"Error: "<<bCnt<<" components"<<endl;
	else{
		for(int i=1;i<=n;i++){
			memset(level,0,sizeof(level));
			memset(visit,false,sizeof(visit));
			dfs(i,i);//深度优先搜索
		} 
		int deepest = 0;
		for(int i=1;i<=n;i++) deepest=max(deepest,maxLevel[i]);
		for(int i=1;i<=n;i++){
			if(maxLevel[i]==deepest) cout<<i<<endl;
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值