【算法基础:搜索与图论】3.6 二分图(染色法判定二分图&匈牙利算法)

文章目录

二分图介绍

https://oi-wiki.org/graph/bi-graph/

二分图是图论中的一个概念,它的所有节点可以被分为两个独立的集合,每个边的两个端点分别来自这两个不同的集合

换句话说,二分图中不存在连接同一集合内两个节点的边

染色法判定二分图

如何判断一个图是二分图?
当且仅当图中不含奇数环。(奇数环指的是环中边的个数是奇数)(因为每一条边都是从一个集合走到另一个集合,只有走偶数次才有可能回到同一个集合。)


染色:相邻的节点的颜色不一样。

因为没有奇数环,所以染色过程是一定不会发生矛盾的。

时间复杂度是 O ( n + m ) O(n + m) O(n+m) , n 表示点数,m 表示边数。

例题:860. 染色法判定二分图

https://www.acwing.com/activity/content/problem/content/926/

使用 dfs 对图中各个节点染色,染色过程中不发生冲突即为二分图。

java 复制代码
import java.util.*;

public class Main {
    static final int N = 100005;
    static List<Integer>[] g = new ArrayList[N];
    static int[] color = new int[N];

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        // 建图
        Arrays.setAll(g, e -> new ArrayList<Integer>());
        for (int i = 0; i < m; ++i) {
            int u = sc.nextInt(), v = sc.nextInt();
            g[u].add(v);
            g[v].add(u);
        }

        // 图可能由多个非连通的子图构成。因此,应该对每一个尚未访问过的点都进行一次深度优先搜索。
        boolean f = true;
        for (int i = 1; i <= n; ++i) {
            if (color[i] == 0 && !dfs(i, 1)) {
                f = false;
                break;
            }
        }
        System.out.println(f? "Yes": "No");
    }

    static boolean dfs(int x, int c) {
        boolean res = true;
        color[x] = c;
        for (int y: g[x]) {
            if (color[y] == 0) res &= dfs(y, 3 - c);
            else if (color[y] == color[x]) return false;
        }
        return res;
    }
}

匈牙利匹配

二分图最大匹配

**二分图最大匹配**

翻译成人话就是------

给定一个二分图 G,即分左右两部分,各部分之间的点没有边连接,要求选出一些边,使得这些边没有公共顶点,且边的数量最大

匈牙利匹配算法思想

两个集合的点数分别是 n1 , n2。

枚举 n1 , 尝试 i 是否可以找到一个 j 完成匹配,匹配成功就 ++cnt。

所以重点 是 find(i) 方法:
对每个 i ,枚举 i 相邻的所有 j ------ 如果 j 没有被匹配就直接返回 true;如果 j 被匹配了,就尝试现在和 j 匹配的另一个 i 能不能换一个 j,能换就换一个然后返回 true;否则返回 false。

时间复杂度是 O ( n ∗ m ) O(n * m) O(n∗m),n 表示点数,m 表示边数。

例题:861. 二分图的最大匹配

https://www.acwing.com/activity/content/problem/content/927/

重点是理解数组 matchst 的含义,以及方法 find(x) 的写法和使用。

java 复制代码
import java.util.*;

public class Main {
    static final int N = 505;
    static int[][] g = new int[N][N];
    static int[] match = new int[N];		// match记录集合2中各个点匹配的集合1的点是哪个
    static boolean[] st = new boolean[N];	// st表示集合2中的点有没有被匹配
    static int n1, n2;

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        n1 = sc.nextInt();
        n2 = sc.nextInt();
        int m = sc.nextInt();
        // 建图
        for (int i = 0; i < m; ++i) {
            int u = sc.nextInt(), v = sc.nextInt();
            g[u][v] = 1;        // 左边的 u 和 右边的 v 之间有一条边
        }

        int cnt = 0;
        for (int i = 1; i <= n1; ++i) {
            Arrays.fill(st, false);		// 重置st
            if (find(i)) ++cnt;
        }

        System.out.println(cnt);
    }

    static boolean find(int x) {
        for (int j = 1; j <= n2; ++j) {
            if (!st[j] && g[x][j] == 1) {
                st[j] = true;
                // 如果 j 还没有匹配或者当前使用 j 的 x 可以让出去
                if (match[j] == 0 || find(match[j])) {
                    match[j] = x;
                    return true;
                }
            }
        }
        return false;
    }
}
相关推荐
罗西的思考1 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX2 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面3 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号3 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽3 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI3 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者5 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者5 小时前
【征程6】校准量化中HistogramObserver解析
算法
OuO-26 小时前
笔试强训 Day 34:ISBN 号码、kotori 和迷宫、矩阵最长递增路径
java·算法·矩阵
程序喵大人6 小时前
【C++进阶】STL算法与函数对象 - 04 find、count和any_of把查询写成意图
开发语言·c++·算法