PAT A1021 Deepest Root

思路:首先利用并查集确定是否能够构成一棵树,即整个图只有一个father。

由于图连通且有n个结点,边数为n-1,可知一定能构成一棵树。

选取任意结点进行DFS得到最大高度的端点,一定为候选的Deepest Root结点,称作集合A。再次从这些集合A的某一个结点出发,得到最大高度的端点集合称作集合B。

可证(详见算法笔记)A与B的并集(注意去重)即为所求的Deepest Root结点集合。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn =10005;

vector<int> G[maxn];
int father[maxn];
int isRoot[maxn];
int n, maxHeight = 0;
vector<int> ans, res;

void init() {
    for(int i = 1; i <= n; i++)
        father[i] = i;
}

int findFather(int x) {
    int temp = x;
    while(x != father[x]) 
        x = father[x];
    int a;
    while(temp != father[temp]) {
        a = temp;
        temp = father[temp];
        father[a] = x;
    }
    return x;
}

void Union(int a, int b) {
    int fa = findFather(a);
    int fb = findFather(b);
    if(fa != fb) father[fa] = fb;
}

int blockNum() {
    int block = 0;
    for(int i = 1; i <= n; i++) 
        if(findFather(i) == i)
            block++;
    return block;
}

void DFS(int idx, int height, int pre) {
    if(height > maxHeight) {
        maxHeight = height;
        res.clear();
        res.push_back(idx);
    } else if(height == maxHeight)
        res.push_back(idx);
    for(int i = 0; i < G[idx].size(); i++) {
        if(G[idx][i] == pre) continue;
        DFS(G[idx][i], height + 1, idx);
    }
}

int main() {
    scanf("%d", &n);
    init();
    int v1, v2;
    for(int i = 0; i < n - 1; i++) {
        scanf("%d %d", &v1, &v2);
        G[v1].push_back(v2);
        G[v2].push_back(v1);
        Union(v1, v2);
    }
    int block = blockNum();
    if(block == 1) {
        DFS(1, 1, -1);
        ans = res;
        DFS(ans[0], 1, -1);
        for(int i = 0; i < res.size(); i++)
            ans.push_back(res[i]);
        sort(ans.begin(), ans.end());
        printf("%d\n", ans[0]);
        for(int i = 1; i < ans.size(); i++)
            if(ans[i] != ans[i - 1])
                printf("%d\n", ans[i]);
    } else {
        printf("Error: %d components\n", block);
    }
    return 0;
}