寒假Day9:二分图的判断+匈牙利算法

二分图匹配相关概念

给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配

极大匹配是指在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数。

最大匹配是所有极大匹配当中边数最大的一个匹配。选择这样的边数最大的子集称为图的最大匹配问题。

如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。

求解算法:求二分图匹配可以用最大流(Maximal Flow)或者匈牙利算法。

注意:完全匹配一定是极大匹配,但是极大匹配不一定是完全匹配。

交替路:从一个未匹配的点出发,依次经过未匹配边、匹配边、未匹配边....这样的路叫做交替路。

增广路:从一个未匹配的点出发,走交替路,到达了一个未匹配过的点,这条路叫做增广路。

看下图,其中1、4、5、7是已经匹配的点,1->5,4->7是已经匹配的边,那么我们从8开始出发,8->4->7->1->5->2这条路就是一条增广路。


二分图的判断

 对于二分图的问题我们首先要判断一个图它是不是二分图。

对于二分图的判断方法最常见的是染色法(对每一个点进行染色操作,我们只用黑白两种颜色,问能不能使所有的点都染上了色,而且相邻两个点的颜色不同,如果可以那么这个图就是一个二分图)。

对于判断是否是一个二分图的方法可以用dfsbfs两种方式去实现。

bfs判断二分图:

 1 bool bfs()//用bfs 判断一幅图是否是二分图
 2 {
 3     memset(col,0,sizeof(col));
 4     //染色后的状态只有1和-1
 5     //所以染色的初始状态为全部清空为0
 6     queue<int> Q;
 7     Q.push(1);//先让第一个点入队
 8     col[1]=1;//给第一个点染色为1
 9     while(!Q.empty())
10     {
11         int p=Q.front();
12         Q.pop();
13         for(int i=0; i<v[p].size(); i++)
14         {
15             //找与第一个点相邻的点
16             int x=v[p][i];
17             if(col[x]==0)//如果未被染色
18             {
19                 col[x]=-col[p];//就染成与当前点相反的颜色
20                 Q.push(x);
21             }
22             else//如果已经被染色了且和当前节点染色相同,则确定不是二分图
23             {
24                 if(col[p]==col[x])
25                     return 0;
26             }
27         }
28     }
29     return 1;
30 }

匈牙利算法

 时间复杂度:O(n*m)

 匈牙利算法模板:

 1 bool dfs(int x)
 2 {
 3     for(int i=0; i<v[x].size(); i++)
 4     {
 5         int s=v[x][i];
 6         if(book[s]==0) // 判断是否标记过,没有被标记进行下一步
 7         {
 8             book[s]=1;
 9             if(f[s]==-1||dfs(f[s]))  // 如果没有被匹配过且能和其他的点进行匹配
10             {
11                 f[s]=x;
12                 return 1;
13             }
14         }
15     } 
16     return 0;
17 }

补充:

  • 匈牙利算法得到的最大匹配并不是唯一的,预设匹配边、或者匹配顺序不同等,都可能会导致有多种最大匹配情况,所以有一种替代KM算法的想法是,我们只需要用匈牙利算法找到所有的最大匹配,比较每个最大匹配的权重,再选出最大权重的最优匹配即可得到更贴近真实情况的匹配结果。但这种方法时间复杂度较高,会随着目标数越来越多,消耗的时间大大增加,实际使用中并不推荐。 
  • 匈牙利算法是最简单最常见的求最大匹配数的算法,但是它的时间复杂度是O(n*m),对于一般的题来说最多有500个点,所以匈牙利是最好的做法。
  • 假如遇到点数更多的话,可以使用Hopcroft-Karp算法,它的时间复杂度是O(n^(1/2) * m)。
  • 以后碰到更深的题目再去学习一下HK算法KM算法(带权二分图的最优匹配问题)匈牙利算法求二分图多重匹配

小知识点:

  • Have all the workers punched in yet?
    所有工人上班都打卡了吗?   punch in 打卡 ~on time  
  • abs是求一个整数的绝对值,fabs是求一个实数的绝对值
  • 数组开小了不会显示RE,会提示超时

可参考博客:

https://blog.csdn.net/dark_scope/article/details/8880547

原文地址:https://www.cnblogs.com/OFSHK/p/12228048.html