染色法+题目:染色法判定二分图

156 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

作用

判断一个图是不是二分图

性质

一个图是二分图,当且仅当图中不含奇数环 奇数环指环中的边数是奇数 由于二分图中不会出现奇数环,所以染色过程是不会出现矛盾的

什么是二分图

image.png 可以将所有点划分到两边,使得集合内是没有边的,集合之间有边

代码

for (i = 1; i <= n; i++) if i 未被染色 dfs(i,1); // 深度优先遍历,将i所在的连通块整个都染一边,染成1号色

题目

www.acwing.com/problem/con… image.png

代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010, M = 200010;

int n, m;
int h[N], e[M], ne[M], idx;
int color[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++; 
}

bool dfs(int u, int c)
{
    // 记录一下当前点的颜色
    color[u] = c;
    
    // 遍历一下当前这个点的所有邻点
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!color[j]) // 如果当前这个点没有染颜色的话	
        {
            if (!dfs(j, 3 - c)) return false; // 表示染色没有成功  
        	// 颜色有两种选择 1 或 2 ,所以用3-c很妙
        }
        else if (color[j] == c) return false; // 跟原来的点颜色一样了,也不ok
    }
    
    return true;
}

int main()
{
    scanf("%d%d", &n, &m);
    
    memset(h, -1, sizeof h); 
    
    while (m--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b), add(b, a); // 因为无向边地原因
    }
    
    // 染色
    bool flag = true; // 标记一下染的时候是否会有矛盾发生,true表示没有矛盾发生
    for (int i = 1; i <= n; i++)
        if (!color[i])// 如果当前这个点没有被染过颜的话
        {
            // 定义:如果dfs返回false,就认为有矛盾发生 
            if (!dfs(i, 1))
            {
                flag = false;
                break;
            }
        }
    
    if (flag) puts("Yes");
    else puts("No"); // 表示有矛盾发生
    
    return 0;
}