最大匹配之匈牙利算法模板。。 (转)
转自:http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2135405.html
要学习匈牙利算法先要懂得二部图的各种概念。。下面给出由o(∩_∩)o MiYu 总结的一般性概念,这些概念很重要,一定要懂。。
二分图的基本概念: ( 意思就是所有的点分成了2个集合 x, y. 每个集合中的顶点相互间没有边 )
一个无向图 G = < V, E >, 如果存在两个集合X, Y, 使得X∪Y=V, X∩Y=Φ, 并且每一条边e={x, y}
有x∈X,y∈Y, 则称G为一个二分图(bipartite graph). 常用来表示一个二分图. 若对X中任一x及Y中任一y
恰有一边e∈E, 使e = {x, y}, 则称G为完全二分图(complete bipartite graph).
二分图的性质: ( 交错轨 和增广路的概念很重要 )
定理:无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数.
匹配:设G=为二分图,如果M⊆E,并且M中没有任何两边有公共端点。M=Φ时称M为空匹配.
盖点: 若M是二分图的一个匹配, 将M中的边多所关联的顶点称为盖点, 其余则为 未盖点.
交错轨: 若一条路径上属于M的边和不属于M 的边交替出现, 则称该路径为交错轨.
增广路径: 若 路径 P 是一条起始点和 终点都是未盖点的交错轨, 那么 P 称为 M 的增广路径.
最大匹配: G的所有匹配中边数最多的匹配称为最大匹配.
性质1 : 一条关于M的增广路径的长度必为奇数, 且路上的第一条边和最后一条边都不属于M.
性质2 : 对于一条关于M的增广路径 P, 将M 中属于P的边删去, 将P中不属于M 的边添加到M中,
所得到的边集合计为 M Θ P, 则 M Θ P 比 M 多一条匹配边.
性质3 : M 为 G 的一个最大匹配当且仅当不存在关于M的增广路径.
hall 定理 : 对于二分图 G = ( X, Y, E ) , 存在一个匹配M, 使得 X 的所有顶点关于M饱和
的充要条件是: 对 X 的任一子集A , 对A邻接的点集为P (A), 恒有 : | P[A] | >= | A |
其中 性质 2 和性质 3 和 hall 定理的充分性证明 就是 匈牙利算法的基础…..
二分图的 最小顶点覆盖 ==== 最大匹配
DAG图的 最小路径覆盖数 == 节点数 – 最大匹配数
二分图的 最大独立集数 = 节点数 – 最大匹配数
在二分图中求最少的点,让每条边都至少和其中的一个点关联,这就是
二分图的“最小顶点覆盖”。
最小路径覆盖 :
一个PXP的有向图中,路径覆盖就是在图中找一些路经,使之覆
盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联;(
如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以
经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每
每条路径就是一个弱连通子集.
由上面可以得出:
1.一个单独的顶点是一条路径;
2.如果存在一路径p1,p2,……pk,其中p1 为起点,pk为终点,那
么在覆盖图中,顶点p1,p2,……pk不再与其它的顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为P的一个路径覆盖.
路径覆盖与二分图匹配的关系(必须是没有圈的有向图):
最小路径覆盖=|P|-最大匹配数;
其中最大匹配数的求法是把P中的每个顶点pi分成两个顶点pi’与pi”,
如果在p中存在一条pi到pj的边,那么在二分图P'中就有一条连接pi’与
pj”的无向边;这里pi’ 就是p中pi的出边,pj”就是p中pj 的一条入边;
对于公式:最小路径覆盖=|P|-最大匹配数;可以这么来理解;
如果匹配数为零,那么P中不存在有向边,于是显然有:
最小路径覆盖=|P|-最大匹配数=|P|-0=|P|;即P
的最小路径覆盖数为|P|;
P'中不在于匹配边时,路径覆盖数为|P|;
如果在P'中增加一条匹配边pi’-->pj”,那么在图P的路径覆盖
中就存在一条由pi连接pj的边,也就是说pi与pj 在一条路径上,于是路
径覆盖数就可以减少一个;
如此继续增加匹配边,每增加一条,路径覆盖数就减少一条;直到
匹配边不能继续增加时,路径覆盖数也不能再减少了,此时就有了前面
的公式;但是这里只 是说明了每条匹配边对应于路径覆盖中的一条路径
上的一条连接两个点之间的有向边;下面来说明一个路径覆盖中的每条
连接两个顶点之间的有向边对应于一条匹配 边;
与前面类似,对于路径覆盖中的每条连接两个顶点之间的每条有向
边pi—>pj,我们可以在匹配图中对应做一条连接pi’与pj”的边, 显然这
样做出来图的是一个匹配图(这一点用反证法很容易证明,如果得到的图
不是一个匹配图,那么这个图中必定存在这样两条边 pi’—pj” 及 pi’ —-pk”,
(j!=k),那么在路径覆盖图中就存在了两条边pi–>pj, pi—>pk ,那边从
pi出发的路径就不止一条了,这与路径覆盖图是矛盾的;还有另外一种情况就
是存在pi’—pj”,pk’—pj”,这种情况也类似可证);
至此,就说明了匹配边与路径覆盖图中连接两顶点之间边的一一对应关系,
那么也就说明了前面的公式成立!
然后是匈牙利的模板:
结合HDU 1240 Asteroids来给出模板:
题意就是把给出点连起来,就是求最小点覆盖
#include <iostream>
#include <math.h>
using namespace std;
#define MAX 502
int map[MAX][MAX];
int n,k;
int mk[MAX];
//从X集合中的顶点u出发用深度优先的策略寻找增广路
//(这种增广路只能使当前的匹配数增加1)
int nx,ny; //X和Y集合中顶点的个数
int cx[MAX],cy[MAX];
//cx[i]表示最终求得的最大匹配中与Xi匹配的Y顶点, cy[i]同理
int path(int u)
{
for(int v=1; v<=ny; v++) //考虑所有Yi顶点v
{
if(map[u][v]&&!mk[v])
{
mk[v]=1;
//如果v没有匹配,或者如果v已经匹配了,
//但从y[v]出发可以找到一条增广路
if(cy[v]==-1|| path(cy[v]))
{
cx[u] = v; //把v匹配给u
cy[v] = u; //把u匹配给v
return 1; //找到可增广路
}
}
}
return 0 ; //如果不存在从u出发的增广路
}
int MaxMatch() //求二部图最大匹配的匈牙利算法
{
int res=0;
memset(cx,0xff,sizeof(cx)); //从0匹配开始增广
memset(cy,0xff,sizeof(cy));
for(int i=1; i<=nx; i++)
{
if(cx[i]==-1) //从每个未盖点出发进行寻找增广路
{
memset(mk,0,sizeof(mk));
res+=path(i); //每找到一条增广路,可使得匹配数加1
}
}
return res;
}
int main()
{
int i,j;
int a,b;
while(cin>>n>>k)
{
nx=n;ny=n;
memset(map,0,sizeof(map));
for(i=0;i<k;i++)
{
cin>>a>>b;
map[a][b]=1;
}
int max=MaxMatch();
cout<<max<<endl;
}
return 0;
}
下面把BFS的模板给出: