一、什么是二分图
首先它需要是一张无向图。
之后它需要同时满足两个条件:①它的N个点被分为两个集合,且这两个集合交集为空;②同一集合内的点之间没有边相连。
二、无向图是否为二分图的判定
引理:无向图是二分图当且仅当图中不存在为奇环。(证明不会略)
方法:基于染色法。如把当前点染为黑色,尝试把与它相邻的点染成白色。若发现和他相邻的点已被染色还不是白色,证明存在奇环,则不是二分图
实现:可用BFS,也可用DFS,复杂度O(N+M)。
1 bool check(int w) 2 { 3 memset(vis,0,sizeof(vis)); 4 queue<int>q; 5 for(int k=1;k<=n;k++) 6 if(!vis[k]) 7 { 8 q.push(k);vis[k]=1; 9 while(!q.empty()) 10 { 11 int x=q.front(); 12 q.pop(); 13 for(int i=head[x];i;i=edge[i].next) 14 if(edge[i].val>=w) 15 { 16 int y=edge[i].to; 17 if(!vis[y]) vis[y]=3-vis[x],q.push(y); 18 else if(vis[y]==vis[x]) return false; 19 } 20 } 21 } 22 return true; 23 }
例题:关押罪犯(丢链接跑)
三、二分图最大匹配
*一些概念:
图的一组匹配:边集。满足“任意两条边都没有公共端点”。
最大匹配:含边数最多的一组匹配。
匹配算法:匈牙利算法(增广路算法/搞对象算法)
(注:增广路这部分不是很懂qwq,鉴于学长的建议等,就先把算法的实现记下了qwq,如果我能苟到省选就再学一遍qwq)
1 bool dfs(int x) 2 { 3 for(int i=head[x];i;i=edge[i].next) 4 { 5 int y=edge[i].to; 6 if(!vis[y]) 7 { 8 vis[y]=1; 9 if(!match[y]||dfs(match[y])) 10 { 11 match[y]=x; 12 return 1; 13 } 14 } 15 } 16 return 0; 17 }
主程序
1 for(int i=1;i<=n;i++) 2 { 3 memset(vis,0,sizeof(vis)); 4 if(dfs(i)) ans++; 5 }
例题1 完美的牛栏 最大匹配裸题
例题2 [ZJOI2009]假期的宿舍 题解链接
******Update:今天写板的时候发现dfs的时候没写vis[x]=1,成功爆掉10-18