【刷题】图论——二分图:染色法【模板】

染色法用于判断是否是二分图

算法原理

  • 二分图:
    结点由两个集合组成,且两个集合内部没有边的图。
    在这里插入图片描述

  • 二分图一定不含奇数环:
    因为每一条边都是从一个集合走到另一个集合,只有走偶数次才可能回到同一个集合。

  • 不含奇数环的一定是二分图:

    • 染色法:当一个点染上黑色,与它相邻的点必须染上白色。同理,染上白色的点,其相邻点必须染上黑色。
    • 由于不存在奇数环,因此染色过程使不存在矛盾的。
      • 只需证其逆否命题成立:如果在染色过程中出现了矛盾,这个环是奇数环。
      • 染色出现矛盾时,一定是某个点染完色,染它相邻的点是发现这个点已经被染过颜色了,并且和这个点颜色相同。
      • 因为染色一定是一黑一白,那么出现两个相同颜色时,将黑白看成一组,一定是n组再加上一个独立的点,即点数是2n+1,这个环是奇数环。

由上面的性质,可以使用 DFS 或者 BFS 来遍历这张图。如果发现了奇环(染色法),那么就不是二分图,否则是。

遍历所有的点和边,时间复杂度是 O ( m + n ) O(m+n) O(m+n)

算法实现

在这里插入图片描述

#include <iostream>
#include <cstring>
using namespace std;

const int N = 100005, M = 200005;
int n, m;
int head[N], lnk[M], nxt[M], idx;
int color[N];
bool flag = true;

void add(int u, int v) {
    lnk[idx] = v;
    nxt[idx] = head[u];
    head[u] = idx ++ ;
}

void dfs(int u, int c) {
    color[u] = c;
    for (int i = head[u]; i != -1; i = nxt[i]) {
        int v = lnk[i];
        if (!color[v]) dfs(v, -c); // v没被染色 
        else if (color[v] == c) flag = false;
    }
}

int main() {
    scanf("%d%d", &n, &m);
    memset(head, -1, sizeof head);
    int u, v;
    for (int i = 1; i <= m; i ++ ) {
        scanf("%d%d", &u, &v);
        add(u, v); add(v, u);
    }
    for (int i = 1; i <= n; i ++ ) {
        if (!color[i]) dfs(i, 1);
    }
    if (flag) printf("Yes\n");
    else printf("No\n");
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值