经典算法 判断一个图是不是树

判断一个图是不是树

问题描述

给一个以0 0结尾的整数对列表,除0 0外的每两个整数表示一条连接了这两个节点的边。假设节点编号不超过100000大于0。你只要判断由这些节点和边构成的图是不是树。是输出YES,不是输出NO。

输入样例1

in 复制代码
6 8  5 3  5 2  6 4 5 6  0 0

输出样例1

in 复制代码
YES

输入样例2

in 复制代码
8 1  7 3  6 2  8 9  7 5 7 4  7 8  7 6  0 0

输出样例2

in 复制代码
YES

输入样例3

in 复制代码
3 8  6 8  6 4 5 3  5 6  5 2  0 0

输出样例3

in 复制代码
NO

输入样例4

in 复制代码
1 2 3 4 0 0

输出样例4

in 复制代码
NO

输入样例5

空树也是树

cpp 复制代码
0 0

输出样例5

in 复制代码
YES

c++代码

cpp 复制代码
#include<bits/stdc++.h>
#include<stdio.h>

using namespace std;

int a, b, cont = 0;
int arr[100001];
bool key = true;
unordered_set<int> st;

int myfind(int x) {
    int root = x;
    while(root != arr[root]) root = arr[root];
    int i = x, j;
    while(i != root) {
        j = arr[i];
        arr[i] = root;
        i = j;
    }
    return root;
}

void mymerge(int x, int y) {
    x = myfind(x), y = myfind(y);
    if (x != y) arr[y] = arr[x];
}

int main() {
    for (int i = 1; i <= 100000; i++) arr[i] = i;
    while(true) {
        scanf("%d %d", &a, &b);
        if (a == 0 && b == 0) {
            if (cont == 0) {
                printf("YES\n");
                return 0;
            }
            if (key && st.size() != cont + 1) key = false;
            if (key) {
                int root = -1;
                for (int x : st) {
                    int k = myfind(x);
                    if (root == -1) root = k;
                    if (k != root) {
                        key = false;
                        break;
                    }
                }
            }
            if (key) printf("YES\n");
            else printf("NO\n");
            break;
        }
        else {
            cont++;
            if (st.find(a) == st.end()) st.insert(a);
            if (st.find(b) == st.end()) st.insert(b);
            if (key) {
                int x = myfind(a), y = myfind(b);
                if (x == y) key = false;
                else mymerge(a, b);
            }
        }
    }
    return 0;
}

算法解析

满足下面三个条件的图是树

1、不存在环。

2、所有点都是互相连通的。

3、点数=边数 + 1。

判断环

用并查集,给每个点一个初始的编号,并初始化所有节点的父亲为本身。每新加入一条边就把边相连的两个集合合并到一起,如果边相连的集合原本就是同一个,说明已经成环,不是生成树。

cpp 复制代码
int x = myfind(a), y = myfind(b);
if (x == y) key = false; //边相连的集合原本就是同一个,说明已经成环,不是生成树。
else mymerge(a, b); //否则合并一下

判断节点数和边数的关系

把点存在一个unordered_set里面就行,因为不能存重复的,边用一个cont就可以存

cpp 复制代码
cont++;
if (st.find(a) == st.end()) st.insert(a);
if (st.find(b) == st.end()) st.insert(b);
......
if (key && st.size() != cont + 1) key = false;

判断连通性

如果是连通的,根据我们之前的合并操作,每一个节点应该都属于同一个集合,如果不是,则不是树。

cpp 复制代码
int root = -1;
for (int x : st) {
    int k = myfind(x);
    if (root == -1) root = k;
    if (k != root) {
        key = false;
        break;
    }
}
相关推荐
电商API_1800790524720 分钟前
速卖通商品采集API技术文章
java·开发语言·c++·api·跨境电商·商品详情
疯狂打码的少年29 分钟前
【数据结构】板块总结 + 下期预告(数据库技术)
数据结构·笔记·算法
郝学胜_神的一滴34 分钟前
Effective Python 条款 2:遵循 PEP 8 编码风格,写出高质量 Python 代码
python·算法
郝学胜-神的一滴35 分钟前
Effective Python 条款 1:确认你正在使用的 Python 版本
开发语言·数据结构·python·程序人生·算法
sel_943 分钟前
【多轮对话论文导读(二)】多轮对话与LLM Agent论文阅读:长期记忆、多轮评估与Agent训练
人工智能·深度学习·算法·语言模型·自然语言处理
一木 之林1 小时前
五、C++新特性、关键字与编译原理
java·jvm·算法
汉克老师1 小时前
CSP-J 初赛(以满分为目标):第四课《看懂计算机到底在算什么!——C++变量、表达式和运算符 》
c++·小学生·学c++编程
小小龙学IT1 小时前
zstd(Zstandard)开源压缩库实战指南:让数据又快又小
c++·开源
小小龙学IT2 小时前
GLM 开源图形学数学库深度解析:从向量、矩阵到四元数的完整实战
c++·矩阵·开源·mfc
dtq04242 小时前
数据结构 - 线性表 - 单链表
数据结构