zoukankan      html  css  js  c++  java
  • AcWing 860. 染色法判定二分图

    题目传送门

    一、二分图的概念

    二分图,是图论中的一种特殊模型,设(G=(V,E))是一个无向图,如果顶点(V)可分割为两个互不相交的子集((A,B)),并且同一集合中不同的两点没有边相连。
    这就是二分图。

    举个栗子吧:
    2.png

    这是不是二分图?
    反正我第一次看觉得不是。其实,是的,他是二分图,尽管看上去是连着的。
    若我们将图中的一些边转一下,变成:
    3.png
    这就是一个明显的二分图。集合A与B中的点互不相连!!!

    只要两个点之间有边,那么这两个点就不能同属一个集合,必须分在两边。

    染色法是判断二分图的最好办法:

    二、DFS实现

    #include <bits/stdc++.h>
    
    using namespace std;
    
    //二分图
    const int N = 100010; //M比给定的要多一倍
    
    int n, m;
    int h[N], e[N << 1], ne[N << 1], idx;
    int color[N];
    
    //邻接表保存图
    void add(int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    //u:点 c:颜色值
    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; //这个3-c用的太妙了
            } else if (color[j] == c) return false; //染色冲突,则表示失败
        }
        return true;
    }
    
    
    int main() {
        //读入优化
        ios::sync_with_stdio(false);
        cin >> n >> m;
        memset(h, -1, sizeof h);//邻接表存储图的方式
    
        while (m--) {
            int a, b;
            cin >> a >> b;
            add(a, b), add(b, a);//无向图,两个方向存储
        }
        //染色
        bool flag = true;//是不是有矛盾发生
        //从前向后染色
        for (int i = 1; i <= n; i++)
            // 如果当前没有被染过颜色
            if (!color[i]) {
                //把当前点染色为1
                if (!dfs(i, 1)) {
                    flag = false;
                    break;
                }
            }
        //是二分图
        if (flag) puts("Yes");
        else puts("No"); //不是二分图
        return 0;
    }
    

    三、BFS实现

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 100010;
    typedef pair<int, int> PII;
    
    int e[N << 1], ne[N << 1], h[N], idx;
    int n, m;
    int color[N];
    
    void add(int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    bool bfs(int u) {
        //假设 1:黑,2:白,这样方便理解一些
        color[u] = 1;
    
        //手写队列
        int hh = 0, tt = 0;
        PII q[N]; //两个属性:节点号,颜色
        q[0] = {u, 1};//将节点u入队列,颜色为黑
    
        while (hh <= tt) {
            PII t = q[hh++];
            int ver = t.first, c = t.second;
            //找到这个节点关联的其它节点
            for (int i = h[ver]; i != -1; i = ne[i]) {
                int j = e[i];
                //没染色就染成相反的颜色
                if (!color[j]) {
                    color[j] = 3 - c;
                    //并且把这个新的节点入队列,再探索其它的相邻节点
                    q[++tt] = {j, 3 - c};
                } else if (color[j] == c) return false;
                //染过的,有两种情况,一种是与本次要求的染色一样,一种是不一样,
                //不一样就是矛盾
            }
        }
        return true;
    }
    
    int main() {
        //读入优化
        ios::sync_with_stdio(false);
        cin >> n >> m;
        //初始化邻接表
        memset(h, -1, sizeof h);
    
        while (m--) {
            int a, b;
            cin >> a >> b;
            add(a, b), add(b, a); // 无向图,两个方向
        }
    
        int flag = true; //一旦发现异常,立即需要报告!
        //遍历每一个节点进行尝试染色
        for (int i = 1; i <= n; i++) {
            //如果还没有进行染色
            if (!color[i]) {
                //染它!并且看看是不是成功完成了染它及其扩展操作
                if (!bfs(i)) {
                    flag = false; //发现异常就不用继续了!
                    break;
                }
            }
        }
        if (flag) puts("Yes");
        else puts("No");
        return 0;
    }
    
  • 相关阅读:
    主外键 子查询
    正则表达式
    css3 文本效果
    css3 2d
    sql 基本操作
    插入 视频 音频 地图
    j-query j-query
    document
    js dom 操作
    js
  • 原文地址:https://www.cnblogs.com/littlehb/p/15337776.html
Copyright © 2011-2022 走看看