题目说明:给出有N个点,N-1条边的图,若图无环连通,找到所有使树的深度最大的树根;若图不连通,则输出连通分量数。
算法:两次dfs。先任选一点A开始dfs,记录所有距离该点最远的点B。此时判断是否所有点都访问过,若是,则图连通,从任一B点开始第2次dfs,记录所有距离B点最远的点C,合并B与C的结果即为所有所求的树根;若图不连通,dfs遍历图,调用dfs的次数就是连通分量数。
代码:
#include<iostream>
#include<fstream>
#include<algorithm>
#include<vector>
using namespace std;
#define MAX 10005
int N;
bool edge[MAX][MAX]={0};
int deepest;
vector<int> deeptemp;
vector<int> deepvec;
bool visit[MAX]={0};
void dfs(int s,int deep){
visit[s]=true;
if(deepest<deep){
deepest=deep;
deepvec.clear();
deepvec.push_back(s);
}
else if(deepest==deep){
deepvec.push_back(s);
}
for(int i=1;i<=N;i++){
if(visit[i]==false&&edge[s][i]){
dfs(i,deep+1);
}
}
}
bool isConnect(){
for(int i=1;i<=N;i++){
if(visit[i]==false){
return false;
}
}
return true;
}
int main(){
cin>>N;
for(int i=0;i<N-1;i++){
int a,b;
cin>>a>>b;
edge[a][b]=edge[b][a]=true;
}
deepest=0;
//第1次dfs,找到距离1最远的点
dfs(1,0);
//判断图是否连通
bool connect=isConnect();
for(int i=1;i<=N;i++)
visit[i]=false;
if(connect){
deeptemp=deepvec;
//第2次dfs
dfs(deepvec[0],0);
//合并第一次与第二次的结果
for(int i=0;i<deeptemp.size();i++){
deepvec.push_back(deeptemp[i]);
}
//排序
sort(deepvec.begin(),deepvec.end());
//删除重复元素
deepvec.erase(unique(deepvec.begin(),deepvec.end()),deepvec.end());
for(int i=0;i<deepvec.size();i++){
printf("%d\n",deepvec[i]);
}
}
else{
int component=0;
//若图不连通,dfs的次数就是连通分量数
for(int i=1;i<=N;i++){
if(visit[i]==false){
component++;
dfs(i,0);
}
}
printf("Error: %d components\n",component);
}
return 0;
}