二分图
二分图判定
二分图,可以把原图的点分为两个集合。对于图中的每一条边,边所连度两个点一定分属于不同的集合。依靠染色法进行二分图的判定,假设对于 \(1\) 染红色,则 \(1\) 所连的其他点都染蓝色。若发现两个点染的颜色相同,则该图不是二分图。
可以使用 DFS、BFS、并查集三种算法判定二分图。
并查集的好处:动态维护效率高。例如对于一张图一直加边,每加一条边就判定其是否是二分图,用并查集维护效率是最高的。
DFS Code
int color[maxn];
bool dfs(int i)
{
for(int j:g[i])
{
if(color[j]==-1)
{
color[j]=color[i]^1;
dfs(j);
}
else if(color[i]==color[j]) return false;
}
return true;
}
// memset(color,-1,sizeof(color));
BFS Code
bool bfs(int s)
{
queue<int> q;
q.push(s);
color[s]=1;
while(!q.empty())
{
int i=q.front();
q.pop();
for(int j:g[i])
{
if(color[j]==-1)
{
color[j]=color[i]^1;
q.push(j);
}
else if(color[j]==color[i]) return false;
}
}
return true;
}
DSU Code
敌对并查集(种类并查集)。
for(int i=1;i<=m;i++)
{
if(judge(u[i],v[i]))
{
ans++;
for(int j=last;j<=i;j++) p[u[j]]=u[j],p[v[j]]=v[j],p[u[j]+n]=u[j]+n,p[v[j]+n]=v[j]+n;
last=i,merge(u[i],v[i]+n),merge(u[i]+n,v[i]);
}
else merge(u[i],v[i]+n),merge(u[i]+n,v[i]);
}
二分图匹配
二分图最大匹配
匹配
图 \(G\) 的一个匹配指对于图 \(G\) 的一个边集,边集中的每条边都不共享同一个顶点,即其中任意两条边在图 \(G\) 中均不相邻。
增广路
在给定一个匹配 \(M\) 的前提下,增广路是一条满足以下条件的路径:
-
起点和终点都是未匹配点,即都不属于当前匹配 \(M\) 中任何一个边的顶点。
-
路径中未匹配边和匹配边交替出现,且路径的第一条边和最后一条边均为未匹配边。
由此可得,增广路除首尾之外的点都是匹配点,且路径中未匹配边数量为 \(k\) 时,已匹配边数量为 \(k-1\)。路径中边度总数为奇数。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1007;
vector<int> g[maxn];
int n,m,mat[maxn];
bool vis[maxn];
bool dfs(int i)
{
for(int j:g[i])
{
if(!vis[j])
{
vis[j]=true; // 标记 Y 部分
if(mat[j]==0||dfs(mat[j]))
{
mat[j]=i;
return true;
}
}
}
return false;
}
int hungary()
{
int res=0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) res++;
}
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int e;
cin>>n>>m>>e;
for(int i=1;i<=e;i++)
{
int u,v;
cin>>u>>v;
g[u].push_back(v+n);
}
cout<<hungary();
return 0;
}

浙公网安备 33010602011771号