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 (≤104) 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);
}
}