读书人

二分图婚配(基础)

发布时间: 2012-12-28 10:29:04 作者: rapoo

二分图匹配(基础)

二分图:又叫二部图,图G中顶点集V可以分成互不相交的子集(X,Y),并且图中的每一条边所关联的点分别属于两个不同的顶点集,则图G叫二分图。(不含奇环)

二分图的匹配:给定一个二分图G的子图M,M的边集中任意两条边都不依附于同一个顶点(点单独配对),则称M是一个匹配。

二分图的最大匹配:边数最大的一个匹配就是二分图的最大匹配。

看上去二分图匹配好像没有什么用途,但以下三个定理会有大用处:

1.二分图的最小点覆盖(x或y中的都行) = 最大匹配;

2.二分图的最大独立集 = 顶点数 - 最大匹配;

(最大独立集是从图中找出最多的顶点数并且顶点两两之间没有边)

3.有向无环图的最小路径覆盖 = 顶点数- 最大匹配。


二分图最大匹配——匈牙利算法

?? 算法的思路是不停的寻找增广路(交错轨),并增加匹配的个数;增广轨的形式:第一条边未参与匹配,第二条边参与匹配,第三条边未参与匹配,...,最后一条边未参与匹配,显然它有奇数条边。那么对于这样一条路径,可以将它变为:第一条边参与匹配,第二条边未参与匹配,第三条边参与匹配,...,最后一条边参与匹配。匹配依然合法,但匹配数增加了一对。可以证明,当找不到增广轨时,就得到了最大匹配,这就是匈牙利算法的思路。

const int N = 50;const int M = 50;bool use[M];//记录y中节点是否使用int link[M];//记录当前与y节点相连的x的节点:i未加入匹配时为link[i]==0bool g[N][M];//记录连接x和y的边,如果i和j之间有边则为1,否则为0int gn,gm;//二分图中x和y中点的数目bool find(int v)//对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;}int MaxMatch()//找二分图的最大匹配数。{    int i,ans=0;    for(i = 1; i <= gn; i++)    {       memset(use,0,sizeof(use));       if(find(i)) ans++;    }return ans;}

?

??? 最小路径覆盖

??? 在有向无环图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,如此增加,直到二分图的最大匹配,也就求出了最小路径覆盖。

?

读书人网 >编程

热点推荐