二分图的学习

前言

在图论里,二分图是一类结构非常特殊、应用极广的无向图。本文用通俗语言讲清什么是二分图、性质、判定方法,最后给出一份简洁可直接使用的 C++ 二分图判定代码。

一、什么是二分图

1. 定义

给定一个无向图,如果可以把图中所有顶点划分成两个互不相交的集合 {U,V},满足:

  1. 所有边的两个端点,一定一个在 U、一个在 V;
  2. 同一个集合内部的点之间没有边相连

满足这个条件的图,就叫做二分图(二部图)

形象理解: 把点分成左右两堆,所有边只能跨左右连,同一边内部不能有边。

2. 等价重要性质(核心)

一个无向图是二分图,当且仅当图中不存在长度为奇数的环(奇环)。

  • 有奇环 → 一定不是二分图
  • 没有奇环 → 一定是二分图

例子:

  • 三角形(3 个点两两相连,环长 3,奇数)→ 不是二分图
  • 一条链、四边形、树(树没有任何环)→ 都是二分图

3. 特殊情况

  • 孤立点(没有任何边的点):可以随便分到任意一侧,不影响二分图性质;
  • 树:所有树都是二分图(无环,自然无奇环)。

二、二分图的判定思路:染色法

思想

尝试用两种颜色给图中每个点染色,要求:

  • 相邻的两个点颜色必须不同;
  • 若染色过程中发现:一个点和已经染色的邻居颜色相同 → 存在奇环,不是二分图。

实现方式常用:DFS / BFS BFS 更安全,不会出现递归深度过大栈溢出的问题。

三、C++ 完整实现

功能:输入无向图,判断是否为二分图,输出结果。

使用说明

  1. 第一行输入点数 n、边数 m;
  2. 接下来 m 行每行输入两个点 \(u,v\),代表无向边;
  3. 程序自动遍历所有连通块,判断是否为二分图并输出。
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int MAXN = 100005;
vector<int> g[MAXN];
// -1未染色,0和1代表两种颜色
int color[MAXN];
int n, m;
bool ok = true;

void bfs(int s) {
    queue<int> q;
    q.push(s);
    color[s] = 0;
    while (!q.empty() && ok) {
        int u = q.front();
        q.pop();
        for (int v : g[u]) {
            if (color[v] == -1) {
                color[v] = color[u] ^ 1;
                q.push(v);
            } else if (color[v] == color[u]) {
                ok = false;
                return;
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    memset(color, -1, sizeof color);
    for (int i = 1; i <= m; ++i) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= n && ok; ++i) {
        if (color[i] == -1) {
            bfs(i);
        }
    }
    if (ok) cout << "Yes, it is a bipartite graph\n";
    else cout << "No, not a bipartite graph\n";
    return 0;
}

四、简单复杂度说明

每个点、每条边只会被访问一次,时间复杂度 \(O(n+m)\),可以处理较大范围的图。

五、拓展:二分图能干嘛?

判定只是基础,二分图常见经典问题:

  1. 二分图最大匹配(匈牙利算法)
  2. 最大独立集、最小顶点覆盖(二分图有对应定理)
  3. 部分网络流问题可转化为二分图模型求解
相关推荐
徐子元竟然被占了!!2 小时前
Git学习
git·学习·elasticsearch
编程圈子2 小时前
电机驱动开发学习1. 直流无刷电机介绍
学习
YM52e2 小时前
鸿蒙PC ArkTS 死亡轮循深度解析与解决方案
学习·华为·harmonyos·鸿蒙·鸿蒙系统
kdxiaojie2 小时前
Linux 驱动研究 —— SPI (2)
linux·运维·笔记·学习
Chris _data2 小时前
# WPF 学习记录( 第二天)
学习·wpf
梦072 小时前
Trae Friends福州线下活动收获一二-vibeCoding现状
经验分享·学习
星恒随风2 小时前
C++ 模板初阶:从泛型编程、函数模板到类模板,一篇打通基础概念
开发语言·c++·笔记·学习
踏着七彩祥云的小丑2 小时前
嵌入式测试学习第35 天:蓝牙、WiFi嵌入式设备测试基础概念
单片机·嵌入式硬件·学习
承渊政道2 小时前
【MySQL数据库学习】(MySQL内置函数)
数据库·学习·mysql·ubuntu·bash·数据库开发·数据库系统