二分图最大匹配(匈牙利算法)
设G=(V,E)是一个无向图,如果顶点V可分割两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
如图就是一个二分图。
二分图匹配,二分图是一种特殊的图结构,所有点分为两类,记做x和y,所有的边的两端分别在x和y,不存在两端同在x或y的边。最大匹配问题即为求最多连接x和y的边的集合。二分图的最大匹配有二种求法:将其规约到网络流问题的网络流和匈牙利算法。
然而前者实现起来比较繁琐,就不提他了。重点讲一下匈牙利算法,最后给个递归的模板。
先讲下增广路概念:若P是图G中一条连通两个未匹配顶点的路径,并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
增广路有下述三个结论:
1。P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
2。P经过取反操作可以得到一个更大的匹配M’。
3。M为G的最大匹配当且仅当不存在相对于M的增广路径。
我们在解决问题时,采用的方法就是从一个顶点出发开始找增广路,找到时对边取反,直到遍历所有顶点时就找到最大匹配了(这里的“所有顶点”只能全都来自x或者y)。
下面是实现找增广路的伪代码:(dfs实现)
bool can(int t)
{
for(int i=0;i<m;i++)
if(!used[i]&&graph[t][i])
{
used[i]=true;
if(link[i]==-1||can(link[i]))
{
link[i]=t;
return true;
}
}
return false;
}
源文档 <file:///C:\Users\Administrator\Desktop\二分图最大匹配.doc>
声明:这是本菜在学习二分图相关知识的时候神小花儿推荐的课件中的知识。现在整理上来和大家分享。
二分图相关问题:
二分图定义及判定
二分图最大匹配
二分图最小覆盖
二分图最大独立集
二分图最小路径覆盖
二分图最优匹配
稳定婚姻问题
一、定义及判定:
定义:二分图中,顶点可以分为两个集合X和Y,每一条边的两个顶点都分别位于X和Y集合中
判定:利用BFS或者DFS进行黑白染色,共享一边的两点异色,检查是否存在矛盾
图G为二分图的充要条件是图中不含奇环
二、二分图最大匹配
定义:匹配是二分图中边的集合,且集合中的任意两条边没有公共点,包含边数最多的匹配就是最大匹配
匈牙利算法:
1、概念:交错路
对于一个匹配M,如果能找到一条奇数长度的路,使得路的第一、三、五……边不属于M,而第二、四、六……边属于M,那么这条路叫做交错路。
交错路可以“增广”,即通过适当修改得到更大的匹配。
2、定理
一个匹配为最大匹配当且仅当匹配中不存在交错路
证明相当繁琐,具体参见组合数学
可以利用BFS或者DFS实现寻找交错路
3、定理的补充
匈牙利算法的实现还依赖于一个很重要的定理:如果从一个点出发,没有找到增广路径,那么无论再从别的点出发找到多少增广路径来改变现在的匹配,从这个点出发都永远找不到增广路径。
4、复杂度
匈牙利算法只需要以每个节点为起点找一次增广路即可求得最大匹配,寻找增广路的复杂度为O(E),总的复杂度为O(VE)
{附上一段我写的朴素Hungary代码}
ProgramHungary;
Const
maxn=10000;
Var
i,n,k,p,q,m,ans:Longint;
pre,other,last:Array[1..maxn*2]of Longint;
state:Array[1..maxn]of Boolean;
res:Array[1..maxn]of Longint;
FunctionDfs(i:Longint):Boolean;
varj,k:Longint;
begin
j:=last[i];
whilej<>0 do
begin
k:=other[j];
if notstate[k] then
begin
state[k]:=true;
if(res[k]=0)or(Dfs(res[k])) then
begin
res[k]:=i;
exit(true);
end;
end;
j:=pre[j];
end;
exit(false);
end;
BEGIN
readln(n,m);
fori:=1 to m do
begin
readln(p,q);
inc(k);pre[k]:=last[p];last[p]:=k;other[k]:=q;
end;
fori:=1 to n do
begin
fillchar(state,sizeof(state),0);
ifDfs(i) then inc(ans);
end;
writeln(ans);
END.
5、简要说明:
简要说明:Dfs函数用于判断从k点开始是否能够找到一条交错路。对于每个可以与k匹配的顶点j,假如它未被匹配,交错路就已经找到;假如j已与某顶点x匹配,那么只需调用Dfs(x)来求证x是否可以与其它顶点匹配,如果返回true的话,仍可以使j与k匹配;这就是一次DFS。每次DFS时,要标记访问到的顶点(state[j]=true),以防死循环和重复计算。
三、二分图最小覆盖
1、定义
图的覆盖:寻找一个点集,使得图中每一条边至少有一点在该点集中
2、定理
二分图的最小覆盖=二分图的最大匹配
3、简要证明
如何构造一组最小覆盖?
求得最大匹配M后,图中已经不存在交错路。从右边未匹配的点开始,以寻找交错路的方式扩展节点,并标记路过的节点。取右边未标记的节点,左边标记的节点,则构成一组最小覆盖。
所取节点数=|M|.右边未匹配的点肯定被标记了,左边未匹配的点不可能被标记(否则找到了交错路),一条匹配边的左端点被标记,那么右端点也肯定被标记,所以所取节点恰覆盖一条匹配边。所取的点覆盖了所有边。假设存在一条边未被覆盖,则该边右端点被标记了,左端点未标记。如果这不是一条匹配边,那么相当于找到了交错路,如果着是一条匹配边,那么右端点只能通过其匹配的左端点到达。
四、二分图最大独立集
1、定义
图的独立集:寻找一个点集,其中任意两点在图中无对应边
一般图的最大独立集是NP完全问题
2、定理
二分图的最大独立集=图的点数-最大匹配数
可以这样理解,在总的点集中,去掉最少的点,使得剩下的点相互之间没有边。用最少的点去覆盖所有的边,也就是最小覆盖。
二分图的最大独立集=图的点数-最大匹配数
五、二分图最小路径覆盖
1、定义
最小路径覆盖问题:用尽量少的不相交简单路径覆盖有向无环图的所有顶点
将每个顶点分为两个,分别在X集合和Y集合中,如果存在有向边(a,b),对应在二分图中有(Xa,Yb)
2、定理
最小路径数=节点数-最大匹配
3、简单证明
原图的路径覆盖和新图的匹配间有对应关系:
每条覆盖边都是匹配中的一条边,且只有路径的最后一个点没有被匹配上。
路径要求不能相交,恰好对应于匹配中两匹配边不能有公共端点。
于是求最大匹配后,不能被匹配上的点,即是路径的最后一个点。有多少个不能被匹配的点,就有多少条路径存在。
路径数=原点数-匹配边数。因此我们使匹配边数最大,即是使路径数最小。
六、二分图最优匹配(又称带权最大匹配)
1、定义
二分图的每条边带有权值。求一个匹配使得匹配边上的权值和最大。
一般X和Y集合顶点个数相同,最优匹配也是一个完备匹配,即每个顶点都被匹配。如果个数不相等,可以通过补点加0边实现转化。
2、基本概念:可行顶标和相等子图
可行顶标:L是一个关于结点的函数,L(x)是顶点x对应的顶标值。可行顶标对于图中的每条边(x,y)都有L(x)+L(y)>=w(x,y)
相等子图:只包含L(x)+L(y)=w(x,y)的边的子图
3、定理
如果一个相等子图中包含完备匹配,那么这个匹配就是最优匹配
证明:由于在算法过程一直保持顶标的可行性,所以任意一个匹配的权值和肯定小于等于所有结点的顶标之和,则相等子图中的完备匹配肯定是最优匹配
4、算法流程
设顶点Xi的顶标为a[i],顶点Yi的顶标为b[i]
ⅰ.初始时,a[i]为与Xi相关联的边的最大权值,b[j]=0,保证a[i]+b[j]>=w(i,j)成立
ⅱ.当相等子图中不包含完备匹配时,就适当修改顶标以扩大相等子图,直到找到完备匹配为止
ⅲ.修改顶标的方法
当从Xi寻找交错路失败后,得到一棵交错树,它的所有叶子节点都是X节点,对交错树中X顶点的顶标减少d值,Y顶点的顶标增加d值,对于图中所有的边(i,j),可以看到
i和j都不在交错树中,边(i,j)仍然不属于相等子图
i和j都在交错树中,边(i,j)仍然属于相等子图
i不在交错树中,j在交错树中,a[i]+b[j]扩大,边(i,j)不属于相等子图
5、时间复杂度
时间复杂度:需要找O(n)次增广路,每次增广最多需要修改O(n)次顶标,每次修改顶标时枚举边来求d值,复杂度为O(n2),总的复杂度为O(n4).
简单优化可以降低到O(n3),每个Y顶点一个“松弛量”函数slack,每次开始找增广路时初始化为无穷大。在寻找增广路的过程中,检查边(i,j)时,如果不在相等子图中,则让slack[j]变成原值与A[i]+B[j]-w[i,j]的较小值。这样,在修改顶标时,取所有不在交错树中的Y顶点的slack值中的最小值作为d值即可。但还要注意一点:修改顶标后,要把所有的slack值都减去d。
i在交错树,j不在交错树中,边(i,j)有可能加入到相等子图中
为了使a[i]+b[j]>=w(i,j)始终成立,且至少有一条边加入到相等子图中,d=min{a[i]+b[j]-w(i,j)},i在交错树中,j不在交错树中
七、稳定婚姻问题
完备婚姻:N位男士和N位女士,组成N对配偶,每位男士按偏爱程度对N位女士排序,每位女士对N位男士也进行排序。
如果存在两对配偶,女士A和男士a,女士B和男士b,使得A更偏爱b而非a,且b更偏爱A而非B,那么就称这个完备婚姻是不稳定的
是否总是存在稳定婚姻?
延迟认可算法
初始每位女士处于未匹配状态。
当存在未匹配女士时,该女士在所有未拒绝过她的男士中选择她最喜欢的男士作为配偶,男士在所有选择他的女士中选择他最喜欢的作为配偶
在该算法中,女士主动选择男士,女士的每次选择都会导致更不理想的配偶,而男士一但被一个他更喜欢的女士选择,则他可以“抛弃”现在的配偶。
每个女士至多选择N次,所以算法一定会终止,时间复杂度为O(N*N)
【后记:感谢神小花儿提供课件,本弱只是做了些整理工作而已,也方便自己阅读了】
源文档 <http://www.cnblogs.com/Thispoet/archive/2011/09/14/2176407.html>
二分图:又叫二部图,图G中顶点集V可以分成互不相交的子集(X,Y),并且图中的每一条边所关联的点分别属于两个不同的顶点集,则图G叫二分图。(不含奇环)
二分图的匹配:给定一个二分图G的子图M,M的边集中任意两条边都不依附于同一个顶点(点单独配对),则称M是一个匹配。
二分图的最大匹配:边数最大的一个匹配就是二分图的最大匹配。
看上去二分图匹配好像没有什么用途,但以下三个定理会有大用处:
1.二分图的最小点覆盖(x或y中的都行) = 最大匹配;
2.二分图的最大独立集 = 顶点数 - 最大匹配;
(最大独立集是从图中找出最多的顶点数并且顶点两两之间没有边)
3.有向无环图的最小路径覆盖 = 顶点数- 最大匹配。
二分图最大匹配——匈牙利算法
算法的思路是不停的寻找增广路(交错轨),并增加匹配的个数;增广轨的形式:第一条边未参与匹配,第二条边参与匹配,第三条边未参与匹配,...,最后一条边未参与匹配,显然它有奇数条边。那么对于这样一条路径,可以将它变为:第一条边参与匹配,第二条边未参与匹配,第三条边参与匹配,...,最后一条边参与匹配。匹配依然合法,但匹配数增加了一对。可以证明,当找不到增广轨时,就得到了最大匹配,这就是匈牙利算法的思路。
const int N = 50;
const int M = 50;
booluse[M]; //记录y中节点是否使用
intlink[M]; //记录当前与y节点相连的x的节点:i未加入匹配时为link[i]==0
boolg[N][M]; //记录连接x和y的边,如果i和j之间有边则为1,否则为0
intgn,gm; //二分图中x和y中点的数目
bool find(intv) //对x中的结点v,找增广路径。
{
int i;
for(i = 1; i <= gm;i++) //对结点v发出的每条边
{
if(g[v][i] && !use[i])
{
use[i] = true;
//如果y中的结点i还没有加入到匹配中(link[i]==0),可直接连线;
//或者y加入到了匹配中,根据link[i]找到x中的结点v,根据v发出的边寻找另外一个未加入匹配结点y
//找到就记录到link中,返回true;找不到返回false(即找增广路径)。
if(link[i] == 0 || find(link[i]))
{
link[i] = v;
return true;
}
}
}
return false;
}
intMaxMatch() //找二分图的最大匹配数。
{
int i,ans=0;
for(i = 1; i <= gn; i++)
{
memset(use,0,sizeof(use));
if(find(i)) ans++;
}
returnans;
}
最小路径覆盖
在有向无环图G中,找出最小的路径条数,使之覆盖所有顶点,且任意一个顶点有且只有一条路径与之关联。从这可以看出:
1.一个单独的顶点是一条路径;
2.如果存在一条路径p1,p2,...,pk,其中p1为起点,pk为终点,那么在覆盖图中,p1,p2,...,pk这些顶点不再与其它的顶点之间存在有向边。
最小路径覆盖就是找出最小的路径条数,使之覆盖所有点。
最小路径覆盖数 = P -最大匹配数。(G必须是无环的有向图)
其中最大匹配数的求法是把G中的每个顶点pi分成两个顶点pi与pi',如果G中存在一条pi到pj的边,那么在二分图G'中就有一条连接pi'与pj'的无向边;这里pi'就是G中pi的出边,pj'就是G中pj的一条入边。
可以这样理解:
匹配数为0,那么图G中不存在有向边,显然有最小覆盖数=P-0=P。
如果在G'中增加一条匹配边pi'-->pj',那么在图G中就有pi-->pj在一条路径上,于是覆盖的路径数减1,如此增加,直到二分图的最大匹配,也就求出了最小路径覆盖。
548

被折叠的 条评论
为什么被折叠?



