作者高一,笔记文章,多有谬误,请多多指教,万分感谢!
二分图概念及性质
什么是二分图
二分图,又称二部图,英文名叫 Bipartite graph。
如果一张无向图的 N (N≥2)个节点,可以分成 A、B两个非空集合,其中 A∩B=Φ,并且在同一集合内的点之间都没有边相连,那么称这张无向图为一张二分图。A、B分别称为二分图 的左部和右部。如下图所示。
二分图的判定
如果两个集合中的点分别染成黑色和白色,可以发现二分图中的每一条边都一定是连接一个黑色点和一个白色点。
定理 一张无向图是二分图,当且仅当图中不存在奇环(边数为奇数的环)
判定 我们可以用染色法进行二分图的判定,尝试用黑白两种颜色标记图中的节点:当一个节点被标记后,它的所有相邻节点应该被标记与它相反的颜色。若标记过程中产生冲突,则说明图在存在奇环。
用DFS或BFS均可,多数用DFS,时间复杂度为O(N+M)。
// 判断是否存在奇环
bool dfs(int now, int fa, int color) {
col[now] = color;
for (int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if (to == fa) continue;
if (col[to] == 0 && !(dfs(to, now, 3-color))) {
return false;
}
if (col[to] == color) return false;
}
return true;
}
// 主函数中
bool flag = true;
for (int i = 1; i <= n; ++i) {
if (!col[i]) {
if (!(dfs(i, 0, 1))) {
flag = false;
break;
}
}
}
if (flag) cout <<"YES"<<endl;
else cout <<"NO"<<endl;
例题 关押罪犯
【分析】
考虑某一个答案为ans时成立时,那么大于ans的答案也一定成立,因此答案具有单调性,可以通过二分答案解决。
设二分的答案为mid,对任意仇恨大于mid的罪犯连边,得到一张无向图,图中的节点需要划分到两个集合,且每个集合中没有边。此时,我们用染色法判定该无向图是否为二分图。根据判定结果,继续二分答案即可。
二分图的应用
二分图的最大匹配
一些概念:
设G=<V, E>是二分图,V是点集,左部集合为V1,右部集合为V2,E是边集,M⊆E。
匹配:若M中任何两条边没有公共点,则称M是G的一个匹配
最大匹配:具有边数量最多的匹配称为最大匹配
最大权匹配:当图中的边带权的时候,边权和最大的为最大权匹配。
匹配中的边称为匹配边,反之称为非匹配边。
一个点如果属于M中至多一条边的端点,称为匹配点,反之称为非匹配点。
完美匹配:若|V1|=|V2|=|M|,则称M为完美匹配
下图中
最大匹配:图 4 是一个最大匹配,它包含 4 条匹配边。
完美匹配:图 4 是一个完美匹配。显然,完美匹配一定是最大匹配(完美匹配的包含了图中的所有点,使得图中每个点都是匹配点)。但并非每个图都存在完美匹配。
再来两个概念:
交错路:从一个未匹配的点出发,依次经过未匹配边、匹配边、未匹配边…这样的路叫做交错路。
增广路:从一个未匹配的点出发,走交错路,到达了一个未匹配过的点,这条路叫做增广路。
增广路的性质:
长度len是奇数
路径上第1、3、5、…、len条边是非匹配边,第2、4、6、…、len-1条边是匹配边
下图中红色边表示匹配边,红色的点表示匹配点
增广路的性质:
长度len是奇数
路径上第1、3、5、…、len条边是非匹配边,第2、4、6、…、len-1条边是匹配边
我们把增广路径上的匹配边与非匹配边状态取反,便会得到一个更大的匹配
结论:二分图的一组匹配S是最大匹配,当且仅当图中不存在S的增增广路。
求最大匹配可以看做是一个舞蹈队的人分成了两个集合,给点集1中的点从点集2中找舞伴,点集1中的点都是男的,点集2中的点都是女的,每个人都有若干个意向的舞伴。
点集1中的男的都很好说话,只要当前给他介绍的女的是单身,就同意匹配;
而且点集1中的男的还很善良,哪怕当前介绍的舞伴不是单身,只要她已经匹配的舞伴可以跟她立马分开,去匹配其他单身的舞伴,他还是可以同意匹配的。
这就是匈牙利算法的大致流程
匈牙利算法(二分图最大匹配算法)动画模拟:
匈牙利算法(二分图最大匹配算法):
设匹配M是空集,即所有边都是非匹配边
寻找增广路path,把路径上所有边的匹配状态取反,得到一个更大的匹配M’
重复第2步,直至图中不存在增广路。
// 参考代码
// 统计最大匹配个数,每找一次增广路,最大匹配加1
int xyl() {
for (int i = 1; i <= n; ++i) {
memset(vis, 0, sizeof(vis));
if (dfs(i)) ++ans;
}
return ans;
}
bool dfs(int x) {
for (int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if (!vis[to]) {
vis[to] = true;
if (!match[to] || dfs(match[to])) {
match[to] = x;
return true;
}
}
}
return false;
}
例:文理分班
【分析】
题目大意是根据学生之间的认识关系,考虑换座位是否冲突。因为只需要考虑本班安排座位的问题,所以原来不是本班的学生一定会来,调走的学生不用管。
如果A认识B,则不管A是本班还是外来,都可以坐在B的位置。
如果某个学生x是本班学生且留在本班,可以认为他自己跟自己换,避免跑匈牙利算法的时候,出现该点无法匹配而判错的情况。但是,外来学生不能自己跟自己换位。
根据可换位的关系,我们构建一张图,跑匈牙利算法,如果发现有匹配不了的,则失败;否则成功。
对于节点i:
如果i被分到其他班,则不用管;
如果i是本班学生且留在本班,则自己可以换到自己的座位;
对于节点i和j,如果i认识j,且j原来是本班的,i到j连边,表示i可以坐到j的位置(如果j是外来的,即使i认识j也没法换位,因为j原本没有位置)。
判断:对没有被分出去的节点跑匈牙利,只要每个节点都能正常匹配即可;否则只要有一个不能匹配则失败。
二分图匹配的模型的两个要素
-
节点能分成独立的两个集合,每个集合内部任意两点之间没有边
-
每个节点只能与 1 条匹配边相连
二分图的最大带权匹配
给定一张二分图,二分图的每条边都有一个权值。求出该二分图的一组最大匹配,使得匹配边的权值总和最大。
这个问题称为二分图的带权最大匹配,也称二分图最优匹配。
注意:二分图带权最大匹配的前提是匹配数最大,然后再最大化匹配边的权值总和。
KM算法
求解的方法:费用流和KM算法,KM算法的局限性在于:它只能在满足“带权最大匹配一定是完美匹配”的图中正确求解。以后基本都用费用流来求解。
END
作者高一,笔记文章,多有谬误,请多多指教,万分感谢!