算法随笔——二分图
定义
节点由两个集合组成,且两个集合内部没有边的图
性质
- 无奇环
- 每条边都是从一个集合走向另一个集合。
二分图判定
使用染色法。
进行
bool vis[N];//0:未染色,1:黑色,2:白色
bool flag= 1;
void dfs(int x)
{
for (auto y : v[x])
{
if (!col[y]) col[y] = 3-col[x],dfs(y);
else if (col[y] != 3-col[x]) flag = 0;
}
}
二分图最大匹配
即找到最多条边使两个集合的点匹配。
使用匈牙利算法。
算法思想是在已有的匹配基础上考虑能否一种新的匹配方式使得匹配数 + 1,俗称增广路。
bool dfs(int x)
{
for (auto y : v[x])
{
if (vis[y]) continue;
if (!p[y] || dfs(p[y]))
{
p[y] = x;
return 1;
}
}
return 0;
}
例题
P3386
没什么好说的,板子题。
int n,m,e;
vector<int> v[N];
int p[N];
bool vis[N];
void add(int x,int y){v[x].push_back(y);}
bool dfs(int x)
{
for (auto y :v[x])
{
if (vis[y]) continue;
vis[y] = 1;
if (p[y]==0 || dfs(p[y]))
{
p[y] = x;
return 1;
}
}
return 0;
}
int main()
{
n = read(),m = read(),e = read();
for (int i = 1;i <= e;i++)
{
int u = read(),v = read();
v += n;
add(u,v);
add(v,u);
}
int ans = 0;
for (int i = 1;i <= n;i++)
{
memset(vis,0,sizeof vis);
ans += dfs(i);
}
cout << ans << endl;
return 0;
}
P2071
挺有意思的二分图匹配变种题。
与二分图正常匹配唯一区别是可以一个点匹配两个点。
做法很简单,就是将一边的点复制一份,这样就变成了一个点匹配一个点了。
CF1139E
感觉是个非常好的题。
非常适合作为二分图的练习题。
我们先考虑将操作倒序,此时变成每次加入一个学生。
然后注意到”校长将会从每个社团中各选出一个人“,若我们将能力值与拥有该能力值的学生所属社团连边,似乎就变成了一个二分图匹配的问题。
但是
想法
时间复杂度
考虑优化,我们发现每次二分判断是否是完全匹配时都会遍历
那么我们其实可以从
时间复杂度
注意到我们每次加入一条边时对于原来已有的匹配是没有影响的,即答案满足单调性。
那么我们每次加边的时候就不需要从
时间复杂度分析:整个算法跑下来相当于只跑了一遍匈牙利,复杂度
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具