参考《啊哈算法》
有一种很特别的图,就做二分图,那什么是二分图呢?就是能分成两组,S,T。其中,S上的点不能相互连通,只能连去T中的点,同理,T中的点不能相互连通,只能连去S中的点。这样,就叫做二分图。
举个很通俗的例子,现在有三个男生和三个女生,要组队一起去报名旅游(情侣报名可以半价哦!),所以,他们就想尽办法凑成一对,就算不是情侣,都说是啦,为了减钱,更可况,我们这些单身狗就是靠这些机会脱单的, ̄□ ̄||。……..为什么可以看成二分图呢?你想啊,男和男在一对,搞基啊?所以,同性的我们规定不能在一起。那么现在问题来了,我现在想知道它们6个人,能组成多少对?这就引入了一个新的问题:二分图的最【大】匹配。顾名思义,就是求二分图中能组成的最大匹配数,比如那6个最多能组成3对,但是能不能组成还是要看条件的。因为小时候爷爷教过我们,不能随便和陌生人打交道嘛,所以我们这里规定,它们只有在认识(就是图能连通) 的情况下,才能组成一对。
现在有男孩:A、B、C
女孩:X、Y、Z
下面给出他们的关系,看清楚那。A认识X、Y
B认识Y、Z 由于C比较内向,只认识X
好啦,现在就要求他们最多能组成多少对啦!唉,为了减钱,费点脑力,值!其实一看就知道了:3对。A—Y B—Z C—X 。但是,我们没办法一下子就得出这个结论的,为什么呢?因为A B C本来互不认识,A也不知道C是不是认识X,所以,A去搭配X或者Y对于A来说是一样的,为什么一定要A搭配Y?所以,我们就算他们不认识,我们也要用算法解他们出来,这就是我们的二分图的最大匹配。现在我们来模拟一下整个过程?首先,A来到X小姐面前,礼貌地问:Could I travel with you? X小姐想都没想,立马答应了(这里我们假设女的一定要答应任何一个男的,为什么?无解,因为我们只是求他们搭配的最大对数,其他的都是次要的,但是我们后面说的最佳匹配,那就不同了)。然后到B先生了,首先,他来到Y中,和Y组合了一起。现在轮到C先生了,C只认识X,然后他去到X小姐身边,说:I wanner ……遗憾的是:X小姐说:我已经和别人组成一队了啊?(怎么办?C先生颜值好像比较高,好想和他一起组队啊……)咦?“你等等,我去问问A先生能不能和别人一起组队先。”X小姐说。然后A先生就只能跑去Y小姐那里了(因为A先生也认识Y小姐),礼貌地问:Could I travel with you? 哇塞!Y小姐最喜欢会说英语的男人了,但是我已经有队伍了啊。咦?你们猜到了吧,如法炮制。对A说:你等等,我问问B能不能和别人组队。然后到B了,他去问Z,我们….能在一起….组队吗?没人搭理的Z小姐当然愿意啦,就说:“我正好空着呢!我们一起吧!”。然后,B就告诉Y,我找到别人啦,88。Y告诉A,我们可以一起去啦,yeah!!!(心想)。然后A告诉X,我找到人啦,886。然后X告诉C,我们可以一起去啦。 ̄□ ̄||…..弄了那么久,终于使匹配数增加一了,这里我们把它叫做增广路。增广路的作用就是“改进”匹配方案(也就是增加匹配对数),那么我们怎么确定他就是最大匹配呢?如果当前匹配方案下再也找不到增广路,那就是最大匹配了,算法如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> int n,m;//顶点数n和边的数目m int e[51][51];//保存一个无向图 int book[51];//每次都标记那个去了和那个没去 int match[51];//标记那个是匹配那个的 #define inf 9999//假设的无穷大 int dfs (int u) { int i; for (i=1;i<=n;i++) { if (book[i]==0&&e[u][i]==1)//这个点在同一次上没去过,而且他们能联通 { book[i]=1;//这个点已经尝试过了 if (match[i]==0||dfs(match[i]))//这个点还没有被匹配, //或者,他可以匹配其他的人 { //他们就能够匹配 match[i]=u;//判断哪个,就是修改那个 //match[u]=i;不用的,错误的 return 1; } } } return 0; } void work () { scanf ("%d%d",&n,&m);//输入顶点数n和边的数目m int i; int j; for (i=1;i<=n;i++) { for (j=1;j<=n;j++) { if (i==j) e[i][j]=0;//初始化 else e[i][j]=inf; } } for (i=1;i<=m;i++) { int u,v; scanf ("%d%d",&u,&v); e[u][v]=1; e[v][u]=1;//无向图 } int i_count=0; for (i=1;i<=n;i++)//尝试遍历每一个顶点 { memset (book,0,sizeof(book)); if (dfs(i)) { i_count++;//若能找到新的匹配,就++ } } printf ("%d\n",i_count); return ; } int main () { work (); system ("pause"); return 0; }