PATA 1021 Deepest Root(25 分)解题报告

本文介绍了一种算法,用于在给定的图中找到所有能使树高度最高的根节点,如果图不是一棵树,则输出连通分量的数量。通过两次深度优先搜索(DFS),算法能够有效地找到所有符合条件的根节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1021 Deepest Root(25 分)

A graph which is connected and acyclic can be considered a tree. The hight 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

作者: CHEN, Yue

单位: 浙江大学

时间限制: 2000 ms

内存限制: 64 MB

代码长度限制: 16 KB

 

题目大意:有时候图可以看做一棵树,选择不同的结点作为树的根节点可以让树高不同,要求找到所有能让树高最高的根节点,如果有多个,就升序输出。如果不是一棵树,就输出他有多少个连通分量。首行给出结点数量N,接下来N-1行给出N-1条边的信息。

解题思路:一棵树有N个结点,必然会有N-1条边,这里题目一定会给出N-1条边,所以判断图是否是一棵树,就是判断整个图是否只有一个连通分量。其次是找根节点的算法:


这个算法的思想是,所有的最大深度点,也就是使得树高最高的点
通过一次DFS,无论从哪个起点开始,找到的【当前】最深点,一定会是一个符合要求的点
然后剩余的点,一定可以通过这个【正确起点】经过深度搜索得到
例如在题目示例中,假设我们从1号开始搜索,得到的【正确起点】会是5
接着我们我们再从5开始搜索,一定可以搜索到3和4是当前最大深度的结点
于是我们就得到了本例的正确答案,3,4,5

简单来说,就是我们进行两次DFS,第一次DFS得到的最深结点集合记为V1,第二次DFS的起点要是V1中的结点,然后进行第二次DFS,把最深的结点记录进V2,V1和V2的并集就是结果。

 

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
const int maxn=10010;
struct node{
	int v;
	int level; 
};
int n;
int maxdepth=0;
bool visit[maxn]={false};
vector<vector<int>> e;//存放图 
vector<int> v;//存放临时结果 
set<int> res;//存放结果 
void DFS(int u,int depth);
int main()
{
	scanf("%d",&n);
	e.resize(n+1);
	int d1,d2;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&d1,&d2);
		e[d1].push_back(d2);
		e[d2].push_back(d1);
	}
	int cnt=0,begin;
	//beign为第一次DFS找到的最深点,也是寻找所有最深点时的起始点 
	//cnt是连通分量的数量,求法是看需要多少次调用DFS才能遍历完所有结点 
	for(int i=1;i<=n;i++)
	{
		if(visit[i]==false)
		{
			DFS(i,1);
			cnt++;
			if(i==1)
			{
				for(int j=0;j<v.size();j++)
				{
					//cout<<"now the v[j] is "<<v[j]<<endl; 
					res.insert(v[j]);
					if(j==0)//第一次遍历的最深点为正确起点 
						begin=v[j];
				}
			}
		}
	}
	if(cnt>1)
		printf("Error: %d components",cnt);
	else
	{
		v.clear();
		memset(visit,false,sizeof(visit));
		DFS(begin,1);//从正确的起点开始遍历,确保能找到所有深度最大的点 
		for(int i=0;i<v.size();i++)
		{
			//printf("after use the correct bot the v is %d\n",v[i]);
			res.insert(v[i]);
		}
		for(auto it=res.begin();it!=res.end();it++)
			printf("%d\n",*it);
	}
	return 0;
}


void DFS(int u,int depth)
{
	visit[u]=true;
	if(depth>maxdepth)//找到了新的最大深度 
	{	//更新最大深度
		//清空临时结果数组v,并把当前结点加入进去 
		maxdepth=depth;
		v.clear();
		v.push_back(u);
	}
	else if(depth==maxdepth)//找到和最大深度相同的点 
		v.push_back(u);
	for(int i=0;i<e[u].size();i++)//递归的访问所有的邻接点 
	{
		int v=e[u][i];
		if(visit[v]==false)
			DFS(v,depth+1);
	}
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值