二分图学习笔记
作者:互联网
不会
定义
设非空无向图 \(G=(V,E)\)。
边独立集/匹配:取边集 \(E(G)\) 的非空子集 \(M\),若 \(M\) 中任意两条边都不相邻(即没有公共点),则称 \(M\) 为 \(G\) 的一个边独立集。
极大边独立集:对于 \(M\),若加入任何一条边 \((u,v)\in E(G)\setminus M\) 后得到的边集 \(M'\) 不再是边独立集,则称 \(M\) 为极大边独立集。
最大边独立集/最大匹配:含有最大边数的边独立集;也可以定义为:若对于 \(G\) 任意的匹配 \(M'\),均有 \(|M'| \leqslant |M|\),则称 \(M\) 为最大匹配。
边独立数/匹配数:最大边独立集所含边数,记作 \(\alpha(G)\)。
完备/完美 匹配:若边独立集 \(M\) 内的边连接的点组成的点集 \(V'=V\),则称 \(M\) 为完美匹配。
\(\texttt{Hungarian}\) (匈牙利)算法
增广路:对于图 \(G\) 的匹配 \(M\),我们称 \((u,v)\in M\) 的边为实边,\((u,v)\notin M\) 的边为虚边,则一条从一个未匹配点出发,经过虚边,实边,虚边...实边,虚边并在一个未匹配点结束的路径为增广路。
增广路的特点是非匹配边一定比匹配边多恰好 \(1\) 条,将增广路“取反”,即匹配边变为非匹配边,非匹配边变为匹配边,可以得到一个比先前匹配数增大 \(1\) 的匹配,因此不断的寻找增广路,可以不断地增加匹配。
#include <bits/stdc++.h>
using namespace std;
const int maxn=505;
int n,m,e;
int edge[maxn][maxn]; // 邻接矩阵表示的图
bool vis[maxn]; // 每个顶点是否已在增广路中
int mx[maxn],my[maxn]; // 与该顶点匹配的另一集合中的顶点
bool dfs(int now) { // now始终是x集合内的点
for(int nxt=1;nxt<=m;++nxt)
if(edge[now][nxt] && !vis[nxt]) {
vis[nxt]=true;
if(!mx[nxt] || dfs(mx[nxt])) {
my[now]=nxt; mx[nxt]=now;
return true;
}
}
return false;
}
inline int Hungarian() {
int ans=0;
for(int i=1;i<=n;++i)
if(!my[i]) {
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>e;
for(int x,y,i=1;i<=e;++i) {
cin>>x>>y;
edge[x][y]=1;
}
cout<<Hungarian()<<endl;
return 0;
}
标签:二分,匹配,增广,int,独立,笔记,学习,maxn,虚边 来源: https://www.cnblogs.com/yangrunxuan/p/15517892.html