ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并查集判断二分图

2022-07-13 12:02:18  阅读:170  来源: 互联网

标签:二分 判断 奇数 int s2 s1 查集 find


原理

首先,一个图是二分图,当且仅当图中不含奇数环。那么我们只要用并查集判断图中是否含有奇数环。

设二分图的两个集合为s1s2,因为集合内不能有边,那么二分图的环首尾相接的边必然是$ s1\rightarrow s2 \rightarrow s1\rightarrow s2\dots $

image

如图所示,如果边是奇数,不能成环。因为如果起点包含在s1中,经过奇数条边,可以推出起点在s2中,矛盾。

并查集实现

将并查集开为点数的两倍,\(1\sim n\)为集合s1,\(n+1\sim 2n\)为集合s2

将所有边连接的点在并查集中合并。因为是无向图,所以我们将每条边\(u\leftrightarrow v\),将s1us2v合并,s1vs2u合并。即uni(u,v+n), uni(u+n,v);

如果是奇数环,会使某个点pp+n合并在一个集合中。那我们就可以用并查集判断奇数环了。

最后会变成这样:

image

多了个对称的联通块。偶数环的两个联通块是独立的;而奇数环有绿色箭头指向红色联通块,红色箭头指向绿色联通块,也就是6个点全部联通了。

代码

struct DSU { //并查集模板
    vector<int> p;
    DSU(int n) : p(n + 1) { iota(p.begin(), p.end(), 0); }
    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
    void uni(int x, int y) { p[find(x)] = find(y); }
    bool same(int x, int y) { return find(x) == find(y); }
};
//直接存边
bool check(int n, int m) {
	DSU dsu(n * 2);
    for (int i = 1; i <= m; ++i) { //合并所有连接的点
        int u = edge[i].u, v = edge[i].v;
        dsu.uni(u, v + n), dsu.uni(u + n, v);
    }
    for (int i = 1; i <= n; ++i) //判断是否有i与i+n在一个集合中
        if (dsu.same(i, i + n))
            return false;
    return true;
}

标签:二分,判断,奇数,int,s2,s1,查集,find
来源: https://www.cnblogs.com/yHan234/p/16473336.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有