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

题目描述

无聊的你回想起了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();
    }
}
相关推荐
To_OC9 小时前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
用户9385156350714 小时前
从 O(n²) 到 O(nlogn):一文读懂快速排序的“快”与“妙”
javascript·算法
To_OC15 小时前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
饼干哥哥15 小时前
Reddit VOC调研太慢?搭一个AI专家团队半小时洞察任何品类|以猫用饮水机为例
人工智能·算法·ai编程
地平线开发者17 小时前
Transformer模型部署之性能优化指南
算法
地平线开发者17 小时前
人在途中:从“编译失败”到“模型可落地”——CUDA 自定义算子
算法·自动驾驶
半个落月20 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星21 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星21 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试