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.
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.
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.
5
1 2
1 3
1 4
2 5
3
4
5
5
1 3
1 4
2 5
3 4
Error: 2 components
题型分类:图的遍历
题目大意:给定N个结点和N-1条边,判断是否构成树,如果为树,找出使树高最大的根节点。根节点不唯一时,以从小到大的顺序输出。
解题思路:
1.判断是否构成一棵树有两种方法:方法①:选一个结点进行遍历,看是否能够遍历完整棵树;方法②:使用并查集的方法,判断两个结点的是否属于同一个集合。
2.寻找使树高最大的根节点,本题也有两种解法:方法α:对每个结点进行暴力求解,求出每个结点作为根节点时整棵树的树高;方法β:任意选取一个结点,对这个结点进行遍历,找出其遍历最深的叶子结点(可能不止一个),我们称其为集合A。从集合A中任意选取一个结点,再对这个选取的结点进行遍历,同样找出其遍历最深的叶子结点(可能不止一个),我们称这个集合为结合B。集合A∪集合B就是最终的答案。方法β需要一定的数学知识,可能并不好理解,但方法β的时间复杂度较小。
本次答案附上以上所有答案的代码。
代码一:方法①+方法α
#include
#include
#include
using namespace std;
const int maxn = 10010;
vector Adj[maxn];
vector deepestRoot;
bool visited[maxn];
int maxHigh = -1, nowHigh = 0;
void DFS(int v, int high);
int main(int argc, char** argv) {
int N;
scanf("%d", &N);
for(int i = 1; i <= N - 1; i++){
int v1, v2;
scanf("%d %d", &v1, &v2);
Adj[v1].push_back(v2);
Adj[v2].push_back(v1);
}
/*查看是否连通*/
int cnt = 0;
memset(visited, false, sizeof(visited));
for(int i = 1; i <= N; i++){
if(visited[i] == false){
DFS(i, 0);
cnt++;
}
}
if(cnt > 1){ //表示不连通
printf("Error: %d components\n", cnt);
return 0;
}
for(int i = 1; i <= N; i++){ //对每个结点进行遍历,将最深的结点纳入答案
memset(visited, false, sizeof(visited));
nowHigh = 0;
DFS(i, 0);
if(nowHigh > maxHigh){ //该结点为根时树高更大
maxHigh = nowHigh;
deepestRoot.clear();
deepestRoot.push_back(i);
}
else if(nowHigh == maxHigh){
deepestRoot.push_back(i);
}
}
for(int i = 0; i < deepestRoot.size(); i++){
printf("%d\n", deepestRoot[i]);
}
return 0;
}
void DFS(int v, int high)
{
if(high > nowHigh){
nowHigh = high;
}
visited[v] = true;
for(int i = 0; i < Adj[v].size(); i++){
if(visited[Adj[v][i]] == false){
DFS(Adj[v][i], high + 1);
}
}
}
代码二:方法②+方法β
#include
#include
#include
#include
using namespace std;
const int maxn = 10010;
vector Adj[maxn];
vector temp; //临时存储集合A和集合B的结点
set deepestRoot;
bool visited[maxn];
int father[maxn], isRoot[maxn];
int maxHigh = -1;
void init(int n);
void Union(int a, int b);
int findFather(int x);
int calBlock(int n);
void DFS(int v, int high);
int main(int argc, char** argv) {
int N;
scanf("%d", &N);
init(N); //并查集初始化
for(int i = 1; i <= N - 1; i++){
int v1, v2;
scanf("%d %d", &v1, &v2);
Adj[v1].push_back(v2);
Adj[v2].push_back(v1);
Union(v1, v2);
}
int block = calBlock(N);
if(block != 1){
printf("Error: %d components\n", block);
}else{
DFS(1, 1);
for(int i = 0; i < temp.size(); i++){
deepestRoot.insert(temp[i]);
}
int newStart = temp[0]; //选取集合A中的一个结点作为根进行遍历
maxHigh = -1; //初始化工作
memset(visited, false, sizeof(visited));
temp.clear();
DFS(newStart, 1);
for(int i = 0; i < temp.size(); i++){
deepestRoot.insert(temp[i]);
}
for(set::iterator it = deepestRoot.begin(); it != deepestRoot.end(); it++){
printf("%d\n", *it);
}
}
return 0;
}
void init(int n){
for(int i = 1; i <= n; i++){
father[i] = i;
}
}
void Union(int a, int b){
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB){
father[faA] = faB;
}
}
int findFather(int x){
int a = x;
while(x != father[x]){ //找到根节点x
x = father[x];
}
while(a != father[a]){ //路径压缩
int z = a;
a = father[a];
father[z] = x;
}
return x;
}
int calBlock(int n){ //计算连通块的数目
int block = 0;
for(int i = 1; i <= n; i++){
isRoot[findFather(i)] = true;
}
for(int i = 1; i <= n; i++){ //累计有多少个根结点
block += isRoot[i];
}
return block;
}
void DFS(int v, int high){
visited[v] = true;
if(maxHigh < high){
temp.clear();
temp.push_back(v);
maxHigh = high;
}else if(maxHigh == high){
temp.push_back(v);
}
for(int i = 0; i < Adj[v].size(); i++){
if(visited[Adj[v][i]] == false){
DFS(Adj[v][i], high + 1);
}
}
}