1. 程式人生 > 實用技巧 >1021 Deepest Root (25分)

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

解釋

給你一個無向圖,找到能夠使得遍歷深度最深的那一些結點,如果有多個,就按結點的序號從小到大輸出。

思路

所以最暴力的想法是以所有的點為根來n遍dfs,最後找到裡面深度最深的那一些點,就好了。
還有一種只需要兩遍dfs就可以的,就是第一次從1號點dfs,然後從裡面得到深度最深的點集s1,然後在從s1中任選一個點dfs,在得到深度最深的點集s2,答案是s1和s2的並集(這個方法要證明一下,有點類似樹的直徑那一題)。
連通圖用並查集判斷。

暴力程式碼

#include<iostream>
#include<cstring>
#include<vector>

using namespace std;

const int N = 10010, M = 20010;

int p[N];
int n;
int h[N], e[M], ne[M], idx;
int w[N], vis[N], mx;

int find(int x){
    if(x != p[x]) p[x] = find(p[x]);
    return p[x];
}

void add(int a, int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u, int d){
    mx = max(mx, d);
    vis[u] = 1;
    for(int i = h[u]; i != -1; i = ne[i]){
        if(vis[e[i]] == 0) dfs(e[i], d + 1);
    }
}

int main(){
    memset(h, -1, sizeof h);
    
    cin >> n;
    
    for(int i = 1; i <= n; i ++) p[i] = i;
    
    for(int i = 1; i < n; i ++){
        int a, b;
        cin >> a >> b;
        add(a, b); add(b, a);
        if(find(a) != find(b)) p[find(b)] = p[find(a)];
    }
    
    int cnt = 0;
    for(int i = 1; i <= n; i ++) if(p[i] == i) cnt ++;
    if(cnt > 1){
        printf("Error: %d components", cnt);
        return 0;
    }
    
    for(int i = 1; i <= n; i ++){
        mx = 0;
        memset(vis, 0, sizeof vis);
        dfs(i, 0);
        w[i] = mx;
    }
    
    for(int i = 1; i <= n; i ++) mx = max(mx, w[i]);
    
    vector<int> res;
    
    for(int i = 1; i <= n; i ++)
        if(mx == w[i]) res.push_back(i);
        
    for(auto t : res) cout << t << endl;
    
    return 0;
}

兩遍dfs程式碼

#include<iostream>
#include<cstring>
#include<set>

using namespace std;

const int N = 100010, M = 200010;

int p[N];
int n;
int h[N], e[M], ne[M], idx;
int w[N], vis[N], mx;

int find(int x){
    if(x != p[x]) p[x] = find(p[x]);
    return p[x];
}

void add(int a, int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u, int d){
    w[u] = d;
    mx = max(mx, d);
    vis[u] = 1;
    for(int i = h[u]; i != -1; i = ne[i]){
        if(vis[e[i]] == 0) dfs(e[i], d + 1);
    }
}

int main(){
    memset(h, -1, sizeof h);
    
    cin >> n;
    
    for(int i = 1; i <= n; i ++) p[i] = i;
    
    for(int i = 1; i < n; i ++){
        int a, b;
        cin >> a >> b;
        add(a, b); add(b, a);
        if(find(a) != find(b)) p[find(b)] = p[find(a)];
    }
    
    int cnt = 0;
    for(int i = 1; i <= n; i ++) if(p[i] == i) cnt ++;
    if(cnt > 1){
        printf("Error: %d components", cnt);
        return 0;
    }
    
    dfs(1, 0);
    
    set<int> res;
    
    for(int i = 1; i <= n; i ++) 
        if(mx == w[i]) res.insert(i);
        
    mx = 0;
    memset(vis, 0, sizeof vis);
    dfs(*res.begin(), 0);
    
    for(int i = 1; i <= n; i ++)
        if(mx == w[i]) res.insert(i);
        
    for(auto t : res) cout << t << endl;
    
    return 0;
}