题目
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即可:执行一次DFS后,判断是否遍历完了(visited数组是否都为true),若没遍历完,则图有多个连通分支,继续从未遍历过的节点DFS,累计连通分支个数,直到把所有节点遍历完为止。
然后找作为根有最大深度的节点。一开始的想法是,分别从所有节点开始DFS遍历,用额外的数组记录每个节点为根时能达到的最大深度,最后输出深度最大的节点们。这个方法虽然也能通过,但比较笨拙,用了n次DFS。
后来参考了柳神的做法,只需两次DFS:将第一次DFS时最深的节点记录到set
里,从中任选一个节点再进行一次DFS,得到最深的节点记录到另一个set
,两个set
的并集即为所求(set
内的元素自动递增排序,且不会insert
重复元素,十分合适)。
每次DFS前,记得将visited复原:
fill(visited.begin(), visited.end(), false);
核心是DFS的写法,如果不用全局变量保存visited的话,需要传入visited的引用,否则递归函数修改的值将无效。下面是示例代码:
vector<vector<int> > E; //全局变量
//深度优先遍历,m是当前节点,visited记录访问情况,depth记录当前迭代深度
void DFS(int m, vector<bool> & visited, int depth){
depth++; //当前迭代层数
visited[m] = true; //当前访问节点
for (int i=0; i<E[m].size(); i++){
//E是邻接表表示的图
if (!visited[E[m][i]]){
DFS(E[m][i], visited, depth);
}
}
return;
}
//调用
DFS(1, visited, 0); //从节点1开始深度遍历
坑
若使用邻接矩阵存储图的话,测试点3会提示内存超限!!! 因为树是稀疏图,所以最好用邻接表存储。
代码
方法一:n次DFS,记录每个节点为根时能达到的最大深度
#include <iostream>
#include <vector>
using namespace std;
vector