一、二分图基础概念
- 定义 二分图(Bipartite Graph)是一种特殊的无向图,其所有顶点可以划分为两个互不相交的集合,满足:图中每一条边的两个端点,都分别属于这两个集合;同一集合内部不存在任何边。 通俗理解:我们可以把图中所有点染成黑白两种颜色,使得任意一条边连接的两个点颜色一定不同,同色点之间没有直接相连的边。
- 核心判定定理 一个无向图是二分图,当且仅当图中不存在长度为奇数的环(奇环)。
偶环(边数为偶数的环):一定可以完成二分染色,属于合法二分图
奇环(边数为奇数的环):染色必然出现冲突,无法构成二分图 最典型的奇环是三角形(3个点、3条边),三个点两两相连,无论如何染色都会出现相邻点同色的情况。 - 常见二分图场景 - 师生关系图、男女配对图 - 跨校交流关系图 - 棋盘黑白格相邻图 - 所有满足"对立关系、分组关系"的无向图
二、算法核心思想
- 二分图染色(又称二染色、黑白染色)是判定二分图的标准方法,执行流程如下:
- 任选一个未访问的起点,将其染成颜色0
- 遍历该点的所有邻居,全部染成颜色1
- 继续遍历邻居的邻居,全部染回颜色0
- 以此类推,深度/广度优先遍历,交替染色
- 遍历过程中若发现相邻点已染色且颜色相同,则判定存在奇环,该图不是二分图
- 颜色状态约定 通常用整数数组标记每个点的状态:
-1:未访问、未染色
0:第一种颜色(对应A)
1:第二种颜色(对应B) - 矛盾判定规则 当遍历到某条边的两个端点时: - 若一端未染色:将其染成另一端的反色,继续遍历 - 若两端都已染色且颜色不同:合法,无冲突 - 若两端都已染色且颜色相同:出现矛盾,存在奇环,不是二分图 ## 三、代码实现模板
三、判断一个图是否为二分图模板
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(ll i=a;i<=n;++i)
#define per(i,a,n) for(ll i=n;i>=a;--i)
typedef long long ll;
const int maxn=1e5+10;
vector<ll> G[maxn];
ll n,m,col[maxn],vis[maxn];
bool flag=1;//是否为二分图
bool dfs(ll x,ll c)
{
col[x]=c;
vis[x]=1;
for(int i=0;i<G[x].size();i++)
{
ll y=G[x][i];
if(!vis[y])dfs(y,!c);//如果y没有被染色,则染成与x不同的颜色
else if(col[y]==c)flag=0;//如果y已经被染色,并且与x颜色相同,则说明不是二分图
}
return true;
}
void sol()
{
cin>>n>>m;
memset(vis,0,sizeof(vis));
rep(i,1,m)
{
ll u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
rep(i,1,n)
{
if(!vis[i])dfs(i,0);
}
if(flag)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
int main()
{
sol();
return 0;
}
四、染色统计与最值计算
-
两集合计数方法 在染色过程中增加计数变量,可以统计每个连通块内两种颜色的节点数量
-
最小/最大选取结论,每个连通二分图都存在两种合法染色方案:
-
起点染0:颜色0数量为cnt0,颜色1数量为cnt1
-
起点染1:颜色0数量为cnt1,颜色1数量为cnt0 因此对于单个连通块:某集合最小节点数 = min(cnt0, cnt1),某集合最大节点数 = max(cnt0, cnt1),全局结果只需将所有连通块的对应值累加即可。
五、经典题型与应用模型
- 二分图合法性判定 题目特征:要求将对象分成两组,组内不能有联系;或明确要求判断是否为二分图。
解法:直接染色,出现矛盾输出无解。
关键词:分组、对立、敌我、不能同组。 - 双集合大小统计题目特征:已知关系为跨集合产生,求两个集合的人数范围。
典型例题:GESP七级「交流问题」------只有不同学校的学生才会交流,求B校最少/最多人数。
解法:每个连通块染色,分别累加所有块的最小值和最大值。 - 最小点覆盖类问题 题目特征:每条边恰好有一端被选中,求最少选中点数。
典型例题:检查点布置问题------每条道路恰好一端设检查点,求最小数量。
解法:约束等价于二分图染色,有奇环则无解;无奇环则每个连通块取最小值累加。
六、高频易错点汇总
- 初始化错误,颜色数组必须初始化为-1,不能默认用0,否则无法区分"未染色"和"颜色0"。
- 遗漏多连通块,** 必须循环遍历所有顶点,只从起点跑一次DFS会漏掉不连通的子图。
- 忘记反色递归,邻居必须染成相反颜色!c,漏写反色会导致所有点同色。
- 用颜色判断连通性,同一连通块内的点可以同色也可以异色,绝对不能用颜色是否相同判断两点是否连通。连通性判断请使用并查集或连通块编号法。
- 大数据栈溢出,节点数量超过范围时,链式图用DFS会爆递归栈,此时必须改用BFS。
- 矛盾不及时终止,发现染色冲突后应及时返回,避免无意义递归造成超时。
七、总结
- 二分图的本质是"无奇环的无向图",二分染色是判定二分图的标准方法。
- 染色算法核心逻辑:"交替染色、冲突判环",DFS和BFS均可实现。
- 每个连通二分图有两种合法染色方案,可用于求解集合大小的最值问题。
- 二分图染色是GESP、CSP-J等竞赛的高频考点,常结合分组、最值、判定类问题出现,掌握模板后可以快速建模求解。