#判断图是否是树#并查集#北京大学复试

https://www.acwing.com/problem/content/3412/

思路:本题需要判断一个图是否为树,这需要我们判断三个要素:

1.一个树的边数应该比节点数少1

2.一个树的节点入度应该小于等于2,且只有一个入度为0的节点即根节点

3.从根节点到任意节点有且仅有一条唯一路线

1我们使用两个计数变量edgecount和vertexcount解决,2我们用入度数组和访问数组解决,3我们用并查集解决,并维护一个布尔型变量记录当前是否判断可以成树

注意点:1.每次完成后需要将数组变量进行初始化防止影响下一步2.将布尔型变量修改后不需要return而是应该继续循环直到所有数据都处理完成

/*树是一种众所周知的数据结构,它既可以是空的(null),也可以是一个节点或多个节点的集合,这些节点通过有向边连接且满足以下属性。
有且仅有一个节点,我们称之为根节点,没有任何有向边指向该节点。
除了根节点外,每个节点都有且仅有一条指向它的边。
从根节点到每个其他节点都有一条唯一的有向边序列。
给定若干个由有向边连接的节点集合的描述,请确定它们是否满足树的定义。
输入格式
输入包含多组测试数据。每组数据占若干行,包含若干个对于有向边的描述,每个有向边的描述包含两个整数 a和 b,
 表示这条有向边从节点 a指向节点 b。当出现数对 0 0 时,表示这组数据的输入结束。当出现数对 -1 -1 时,表示全部输入结束。
输出格式:每个数据输出占一行,表示结果。格式为 Case k is a tree. 或 Case k is not a tree.,其中 k为组别编号,从 1开始。
数据范围0<a,b<10000,每个输入最多包含 100 组数据。
输入样例
6 8  5 3  5 2  6 4
5 6  0 0*/
#include <bits/stdc++.h>

using namespace std;
int father[10001];
void initialize(int n) {
    for (int i = 0; i < n; i++) {
        father[i] = i;
    }
}

int findele(int u) {
    if (u == father[u]) { //节点的下标与数组值相等,即为找到了根节点
        return u;
    } else {
        father[u]=findele(father[u]);//继续向上找
        return father[u];
    }
}
void Unionele(int i, int j) {
    int uroot;
    uroot = findele(i);
    int vroot;
    vroot = findele(j);
    father[vroot] = uroot;
}

int main() {
    int u,v;
    initialize(10001);
    int edgeCount = 0;//边数
    int vertexCount = 0;//顶点数
    vector<int> vertex(10001); // vertex[i] -> 0 说明 i 未出现过
    vector<int> inDegree(10001); // inDegree[i] 记录i的入度
    bool isOK = true;
    int caseIdx = 1;
    while(1){
        scanf("%d%d",&u,&v);
        if(u==-1&&v==-1){ //整个输出结束
            break;
        }
        else if(u==0&&v==0){ //单次输出结束
            if(vertexCount!=edgeCount+1){
                isOK = false;
            }
            if(vertexCount == 0&&edgeCount == 0){
                isOK = true;
            }
            if(isOK == true){
                printf("Case %d is a tree.\n",caseIdx);
            }
            else{
                printf("Case %d is not a tree.\n",caseIdx);
            }
            initialize(10001);
            edgeCount=0;
            vertexCount = 0;
            for (int i = 0; i < 10001; ++i) {
                vertex[i] = 0;
                inDegree[i] = 0;
            }
            isOK = true;
            ++caseIdx;
        }
        else{//继续输入
            edgeCount++;
            if(vertex[u] == 0){
                vertex[u] = 1;
                ++vertexCount;
            }
            if(vertex[v]==0){
                vertex[v] = 1;
                ++vertexCount;
            }
            if(findele(v)== findele(u)){
                isOK = false;
            }
            else{
                Unionele(u,v);
            }
            ++inDegree[v];
            if(inDegree[v]>=2){
                isOK = false;
            }
        }
    }
    return 0;
}

全部评论

相关推荐

jack_miller:我给我们导员说我不在这里转正,可能没三方签了。导员说没事学校催的时候帮我想办法应付一下
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务