求树直径及所有直径顶点

思路: 先从树中任意选择一个顶点。由于树具有任意两个顶点连通的性质,利用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 }
posted @ 2020-01-01 16:48  popozyl  阅读(358)  评论(0编辑  收藏  举报