图论三元环(并查集的高级应用)

题目描述

无聊的你回想起了A题的三角形,于是你想到了一个新的问题:

在一个连通图中,任何一条边都属于一个集合

如果两条边 a,b属于同一个集合当且仅当满足以下条件之一

  1. a,b 是某一个三角形的两条边

  2. 存在边 c ,使得 a,c 属于同一个集合且 b,c 属于同一个集合

那么请问,以下连通图的所有边是否都属于同一个集合?

输入描述:

第一行输入 T,表示 T 组样例

每组样例第一行输入两个正整数 n,m

接下来 m 行,第i行输入两个正整数 ai,bi​,表示第i条边连接 ai,bi​结点

数据保证图联通,且没有重边和自环

输出描述:

输出一个字符串表示答案

是输出 "Yes"

否输出 "No"

示例1

输入

复制代码
1
3 3
1 2
1 3
3 2

输出

复制代码
Yes

示例2

输入

复制代码
1
4 5
1 2
1 4
2 3
2 4
3 4

输出

复制代码
Yes

示例3

输入

复制代码
1
3 2
1 2
1 3

输出

复制代码
No

示例4

输入

复制代码
1
4 4
1 2
1 4
2 3
3 4

输出

复制代码
No

先放在这里

代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std; // 引入 std 命名空间

using i64 = long long;
using u64 = unsigned long long;

void solve() {
    int n, m;
    cin >> n >> m;
    vector<int> p(m + 1);

    auto find = [&] (auto self, int &x) -> int {
        if (x == p[x]) return x;
        return p[x] = self(self, p[x]);
    };

    auto merge = [&] (int &a, int &b) -> void {
        int fa = find(find, a), fb = find(find, b);
        if (fa != fb) {
            p[fb] = fa;
        }
    };

    vector<int> in(n + 1), u(m + 1), v(m + 1);

    for (int i = 1; i <= m; i++) {
        cin >> u[i] >> v[i];
        in[u[i]]++;
        in[v[i]]++;
        p[i] = i;
    }

    vector<vector<pair<int, int>>> e(n + 1);

    for (int i = 1; i <= m; i++) {
        if (in[u[i]] < in[v[i]] || (in[u[i]] == in[v[i]] && u[i] < v[i])) {
            e[v[i]].push_back({u[i], i});
        } else {
            e[u[i]].push_back({v[i], i});
        }
    }

    vector<pair<int, int>> vis(n + 1);

    for (int i = 1; i <= n; i++) {
        for (auto [x, j] : e[i]) vis[x] = {i, j};

        for (auto [x, j] : e[i]) {
            for (auto [y, k] : e[x]) {
                if (vis[y].first == i) {
                    merge(k, j);
                    merge(j, vis[y].second);
                }
            }
        } 
    }

    int ans = 0;
    for (int i = 1; i <= m; i++) {
        if (p[i] == i) ans++;
    }

    if (ans == 1) cout << "Yes\n";
    else cout << "No\n";
}

int main() {
    ios::sync_with_stdio(0);
    cout.tie(0);
    cin.tie(0);

    i64 t = 1; 
    cin >> t;
    while (t--) {
        solve();
    }
}
相关推荐
Cx330❀5 分钟前
【优选算法必刷100题】第43题(模拟):数青蛙
c++·算法·leetcode·面试
杜子不疼.5 分钟前
【LeetCode30_滑动窗口 + 哈希表】:三招搞定“串联所有单词的子串”
数据结构·算法·哈希算法
闻缺陷则喜何志丹5 分钟前
【C++动态规划 状压dp】1879. 两个数组最小的异或值之和|2145
c++·算法·动态规划·力扣·数组·最小·动态规范
艾莉丝努力练剑10 分钟前
【优选算法必刷100题:专题五】(位运算算法)第033~38题:判断字符是否唯一、丢失的数字、两整数之和、只出现一次的数字 II、消失的两个数字
java·大数据·运维·c++·人工智能·算法·位运算
光羽隹衡10 分钟前
机器学习——DBSCAN算法
人工智能·算法·机器学习
vyuvyucd11 分钟前
Java数组与Arrays类实战指南
数据结构·算法
csuzhucong11 分钟前
七彩鹦鹉螺魔方
算法
逝川长叹11 分钟前
利用 SSI-COV 算法自动识别线状结构在环境振动下的模态参数研究(Matlab代码实现)
前端·算法·支持向量机·matlab
山上三树11 分钟前
详细介绍 C 语言中的匿名结构体
c语言·开发语言·算法
EXtreme3512 分钟前
【数据结构】彻底搞懂二叉树:四种遍历逻辑、经典OJ题与递归性能全解析
c语言·数据结构·算法·二叉树·递归