1021 Deepest Root (25分)
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遍历一个结点后,查看有无未遍历的结点,遍历后继续查看,即可算出连通子图个数;
判断环: 若连通,则边个数为N-1说明无环,若边个数为N-1,有K个最大连通子图即有K-1个环;
解法1:暴力法
对每个结点进行dfs,记录dfs高度最大的结点,且每次dfs后做连通判断;
1.输入函数,建图
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N;
//若不连通,写出有几个子图
vector<vector<int>> Graph;
void input()
{
cin>>N;
Graph.resize(N+1);
int a,b;
for(int i=0;i<N-1;i++)
{
cin>>a>>b;
Graph[a].push_back(b);
Graph[b].push_back(a);
}
}
2.dfs函数
遍历每个点,同时统计最高高度;
void dfs(int n,vector<int> &visited,int t) //遍历的点,visited函数,层数
{
if(visited[n]) return;
visited[n]=1;
if(t>T) T=t;
for(int i:Graph[n])
{
dfs(i,visited,t+1);
}
return;
}
3.操作函数process
int T; //单次遍历的最高层数
void dfs(int n,vector<int> &visited,int t);
void process()
{
vector<int> visited(N+1,0);
int cnt=1; //统计连通子图数;
vector<int> Hroot;
int MAXT=0;
bool flag=0;
for(int i=1;i<=N;i++) //将每个结点作文根节点尝试
{
fill(visited.begin(),visited.end(),0); //不能用resize赋值
T=0;
dfs(i,visited,0);
if(T>MAXT)
{
Hroot.clear();
MAXT=T;
Hroot.push_back(i);
}
else if(T==MAXT) Hroot.push_back(i);
for(int j=1;j<=N;j++)//遍历visited,看有无不连通的子图
{
if(!visited[j])
{
dfs(j,visited,0);
cnt++;
flag=1;
}
}
if(flag) break;
}
if(flag) cout<<"Error: "<<cnt<<" components"<<endl;
else
for(int num:Hroot) cout<<num<<endl;
}
4.main函数
int main(){
input();
process();
}
解法2:dfs一个节点,得到最大高度的叶节点,再dfs该叶节点之一,得到最大高度的叶节点,两者集合即为最大高度的根节点的集合
C++ (g++) 45 ms 速度快的多
先判断是否连通;
若连通,再对随机一个结点进行dfs,dfs函数里增加保存最深叶节点的操作;
注意初始化即可;
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
using namespace std;
int N;
//若不连通,写出有几个子图
vector<vector<int>> Graph;
void input()
{
cin>>N;
Graph.resize(N+1);
int a,b;
for(int i=0;i<N-1;i++)
{
cin>>a>>b;
Graph[a].push_back(b);
Graph[b].push_back(a);
}
}
int T; //单次遍历的最高层数
vector<int> result;
void dfs(int n,vector<int> &visited,int t);
void process()
{
set<int> res; //存放并集
vector<int> visited(N+1,0);
int cnt=1;
bool flag=0;
dfs(1,visited,0);
for(int j=1;j<=N;j++)//遍历visited,看有无不连通的子图
{
if(!visited[j])
{
dfs(j,visited,0);
cnt++;
flag=1;
}
}
if(flag) {
cout<<"Error: "<<cnt<<" components"<<endl;
return;
}
//dfs一个点
fill(visited.begin(),visited.end(),0);
result.clear();
dfs(1,visited,0);
for(int i:result) res.insert(i);
fill(visited.begin(),visited.end(),0);
dfs(result[0],visited,0);
for(int i:result) res.insert(i);
for(int num:res) cout<<num<<endl;
}
void dfs(int n,vector<int> &visited,int t) //遍历的点,visited函数,层数
{
if(visited[n]) return;
visited[n]=1;
if(t>T) {
result.clear();
result.push_back(n);
T=t;
}
else if (t==T) result.push_back(n);
for(int i:Graph[n])
{
dfs(i,visited,t+1);
}
return;
}
int main(){
input();
process();
}