PTA A1021(DFS+并查集)

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.

输入文件:每个输入文件包含一个测试样例,针对每个测试样例,第一行包含正整数N,它是节点的数量,因此结点从1到N 接下来N-1行,每个描述两个节点的数据。

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.

输出规格:针对每个测试文件,在一行打印最深的根节点,如果这个结点不唯一,以递增的序列打印1他们,防止样例给的图不是树,打印错误 图响铃的个数。
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

核心思路

首先用领接表存储它并查集+dfs,联通分量如果大于属于error,其余正常操作

完整代码

//1、每读入一条边的两个端点,判断这两个端点是否属于相同的集合(即集合的根节点是否相同)
//2、如果不同,则将它们合并到一个集合中.这样,当处理完所有边后就可以根据最终产生的集合个数是否为1来判断
//给定的图是否联通
//3、当图联通时,由于题目保证只有N-1条边,因此一定能确定一棵树
//任意选择一个结点,从1该节点开始遍历整棵树,获取能达到的最深的顶点(记为结点集合A),
//然后从集合A中任意一个结点出发遍历整棵树,获取能达到最深的顶点
#include
#include
#include
#include
using namespace std;
const int N = 100010;
vector<int>G[N];//领接表

bool isRoot[N];//记录每个结点是否作为某个集合的根节点
int father[N];
int findFather(int x){//查找x所在集合的根节点
    int a = x;
    while(x != father[x]){
        x = father[x];
    }
    while(a != father[a]){
        int z = a;
        a = father[a];
        father[z] = x;
    }
    return x;
}

void Union(int a,int b){//合并a和b所在的集合
    int fa = findFather(a);
    int fb = findFather(b);
    if(fa != fb){
        father[fa] = fb;
    }
}

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

int calBlock(int n){
    int Block = 0;
    for(int i =1;i<=n;i++){
        isRoot[findFather(i)] = true;//i的根节点是findFather[i]
    }
    for(int i =1;i<=n;i++){
        Block += isRoot[i]; //累加根节点个数.
    }
    return Block;
}

int maxH = 0; //最大高度
vector<int> temp,Ans;//temp暂时存放dfs的最远结点结果,ans保存答案。

void DFS(int u,int Height,int pre){
    if(Height > maxH){//如果获得更大的树高
        temp.clear();//清空temp
        temp.push_back(u);//将当前结点u加入temp中
        maxH = Height; //将最大树高赋给maxH
    }else if(Height == maxH) {//如果数高等于最大树高
        temp.push_back(u);
    }
    for(int i =0;i<G[u].size();i++){//遍历u的所有子节点
        //由于邻接表中存放无向图,因此需要回去的边
        if(G[u][i] == pre) continue;
        DFS(G[u][i],Height+1,u);//访问子结点
    }
}
int main(){
    int a,b,n;
    scanf("%d",&n);
    init(n);
    for(int i = 1;i<n;i++){
        scanf("%d%d",&a,&b);
        G[a].push_back(b);
        G[b].push_back(a);
        Union(a,b);
    }
    int Block = calBlock(n);//计算集合数目
    if(Block != 1){ // 不止一个连通块
        printf("Error: %d components\n",Block);
    }else{
        DFS(1,1,-1); //从11号结点开始DFS,初始高度为1
        Ans = temp;                // temp为集合A,赋给Ans
        DFS(Ans[0],1,-11); // 从任意一个根节点开遍历
        for(int i =0;i<temp.size();i++){
            Ans.push_back(temp[i]); //此时temp为集合B,将其加到ANs中
        }
        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]);
            }
        }
        return 0;
    }
}

你可能感兴趣的:(考研C集,浙大pta,深度优先,算法)