求树直径及所有直径顶点
思路: 先从树中任意选择一个顶点。由于树具有任意两个顶点连通的性质,利用DFS或BFS可求出与1距离最远的顶点的集合A,它们都是直径的顶点,但是此时直径长度没有确定、且无法保证求出了所有的直径顶点,需要再次搜索。从第一次搜索所得到的直径顶点中,任意取一个,再次DFS or BFS,得到新的顶点集合B。 将A与B取并集即为所有的直径顶点。(注意:两次搜索即可)
算法正确性证明参考 :
https://blog.csdn.net/wdq347/article/details/9328291
另外补充: 如果要求图中存在几个不相交环,可以使用并查集。
以PAT的一道题目为例 : https://pintia.cn/problem-sets/994805342720868352/problems/994805482919673856
AC 代码 :
1 #include <iostream> 2 #include <queue> 3 #include <set> 4 #include <vector> 5 #define Maxsize 10000 + 1 6 using namespace std; 7 vector<int> next_p[Maxsize]; 8 set<int> poss; 9 int find_mid = -1; 10 int max_dis = -1; 11 bool vis[Maxsize]; 12 int book[Maxsize]; 13 int find_f(int a){ 14 if(book[a] == a)return a; 15 else return book[a] = find_f(book[a]); 16 } 17 void Union(int a,int b){ 18 int fa = find_f(a); 19 int fb = find_f(b); 20 book[fa] = fb; 21 } 22 void DFS(int now,int step){ 23 for(vector<int> :: iterator it = next_p[now].begin(); it not_eq next_p[now].end(); it++){ 24 if(vis[*it] == true)continue; 25 vis[*it] = true; 26 DFS(*it, step+1); 27 vis[*it] = false; 28 } 29 if(step > max_dis){ 30 poss.clear(); 31 poss.insert(now); 32 max_dis = step; 33 }else if(step == max_dis){ 34 poss.insert(now); 35 } 36 return; 37 } 38 int main(){ 39 int vertex; 40 cin >> vertex; 41 for(int i = 1; i <= vertex; i++)book[i] = i; 42 int cnt = 0; 43 int pa,pb; 44 /* 读入边的信息 */ 45 while(cin >> pa >> pb){ 46 Union(pa, pb); // 并查集合并顶点 47 next_p[pa].push_back(pb); 48 next_p[pb].push_back(pa); // 记录边 49 } 50 /* 并查集判断 */ 51 set<int> dict; // 记录 52 for(int i = 1; i <= vertex; i++){ 53 if(dict.count(find_f(i)))continue; 54 else { 55 dict.insert(find_f(i)); 56 cnt++; 57 } 58 } 59 if(cnt not_eq 1){ 60 cout<<"Error: "<<cnt<<" components"; 61 return 0; 62 } 63 /* 求解直径顶点 */ 64 vis[1] = true; // 先选择 1 65 DFS(1,0); 66 set<int> ans = poss; // 保留集合A的解 67 68 /* 记得初始化 */ 69 fill(vis, vis+vertex+1, false); 70 vis[*poss.begin()] = true; 71 DFS(*poss.begin(),0); 72 /* 取并集 */ 73 for(set<int> :: iterator it = poss.begin(); it not_eq poss.end(); it++)ans.insert(*it); 74 75 /* 遍历输出,set 自动排序 */ 76 int first = 1; 77 for(set<int> :: iterator it = ans.begin(); it not_eq ans.end(); it++){ 78 if(first)first = 0;else cout<<endl; 79 cout<<*it; 80 } 81 return 0; 82 }
---- suffer now and live the rest of your life as a champion ----