我一般来讲是不会怎么去写关于算法类的总结或者说是讲解的,原因么,我也不知道……可能嫌讲解时候还要画图比较麻烦吧,呵呵^_^。这篇讲解算是我在算法类的第一篇,讲得不好的地方,欢迎直接在我的博客下方直接指出(反正我上博客的时间不多[滑稽])。为什么要写这篇讲解呢,因为我在研究这个二分图最大匹配问题的时候,好像研究了一下午,但是,我感觉我至少有90%的时间是在纠结于这个二分图到底是个啥玩意儿,像百度百科之类的学术性太强的讲解我表示呵呵(不过有可能这跟我是个蒟蒻有点关系),而又有大部分网友写的博客是直接调用了百度百科上对于二分图的解释,所以我就只能自己去摸索,摸索到最后,我才发现这玩意儿原来这么**容易。废话不多说了(好像已经说了蛮多了),开讲。
在A市的B学校中,C年级7班是个十分社会的班级,具体表现在把小猪佩奇纹在身上之类的……7班一共有10个男生,分别是1,2,3,4,5,6,7,8,9,10,这十个男生看上了五个女生,所以这十个男生成天看对方不顺眼,突然有一天,1拉拢了2,3,4,5,他们想要组成一个群体,把其他的男生都教训一遍,我们先来说明一下:
假设X男生和Y男生相互有敌意,可以用以下几种方式表现:
(1):
(2):
(3):
其它五个男生一看势头不对,马上也抱了个团……这样的话班里十个男生被分成了两组,每组中的成员对其他成员均没有敌意,这样子根据上面的表现形式,我们可以得出一幅图:
发现了吗这个图是不是看的你眼花缭乱,对这就是我的意图,呵呵,这两组中的任何一组成员之间都没有连线,即这两组中任何一个元素与其他同组元素都没有关联,这样的图我们把他们称之为二分图,反正我是这么理解的(大佬们怎么理解的我反正晓不得)
社会7班在10个男生在一个月黑之夜打了一场群架,第一组男生把第二组男生打趴下了(可能第二组男生有几个坑队友),现在第二组男生对班里的5个女生不敢垂涎了^_^,那么我们知道的,女生长得有漂亮的,还有些长得可能有点着急,所以男生们并不是对所有女生都有好感,我们先来说明一下: 假设X男生喜欢Y女生,可以用以下几种方式表现: (1):
(2):
(3):
现在,我们获悉了这些男生对班里女生的喜欢情况:
看到了吧,这一次并不是所有人都会被匹配的,比如可怜的女5,这5个男生没有一个喜欢她,所以她肯定不会被匹配到,那么有5个男生,4个女生,僧多粥少,这样的话肯定就有一个可怜的人不会被匹配到了T_T,现在这5个男生找到了Mr.Wang,想让Mr.Wang帮他们匹配女生(排除女生不喜欢男生的情况),使得最后脱单的男生越多越好(我们假设这5个男生全部单身),值得一提的是,每个男生最多只能匹配到一个女生(想要建立后宫的男生就放弃吧)。好了,作为最公正的Mr.Wang,他要开始匹配了:
第一步:Mr.Wang找到了男1,告诉他你跟女1可以在一起了(呵呵),男1开开心心地接受了。
第二步:Mr.Wang发现男2也喜欢女1,没办法,Mr.Wang只能去找男1,告诉他你去跟女2在一起吧,女1让给男2咋样?男1开开心心地接受了(脾气好的诡异),然后男2也开开心心地和女1在一起了。
第三步:Mr.Wang看到了男3对女1垂涎已久,所以不忍让男3就此成为单相思,Mr.Wang只能让男2去跟女4在一起了,而男3也就如愿以偿了。
第四步:Mr.Wang发现男4十分纯情,男4只喜欢女4一人,所以,Mr.Wang开始了超级调度模式:首先Mr.Wang告诉占有女4的男2,让他重新和女1重续前缘,但是呢,男3就没女生可以匹配的了,不急,男3之前还喜欢着女2呢,所以Mr.Wang让男3跟女2在一起了,那么问题又来了,男1又和哪个女生在一起呢?呵呵,其实男1还可以女3呆在一起,而女3目前没有和任何男生在一起,所以调度成功完成!
第5步:Mr.Wang带了把防身用的小刀去告诉男5他没有女生可以匹配了,一边凉快去吧。
走了以上5步,我们惊讶地发现这5个男生被最大限度地匹配到了各自的伴侣,而且没有比这个更优的匹配方案了(除非有新的女生插班)。总结一下:男生们给Mr.Wang出的难题就是二分图的最大匹配问题,而Mr.Wang的匹配方法就是著名的匈牙利算法。通过观察Mr.Wang(匈牙利算法)的行为,发现想法其实不难,如果当前女生还没有被匹配过,那么就直接匹配,否则就递归把所有有关的男生全部匹配另外的女生,如果没有办法,那么就只能让那位老兄一边凉快去了。引用我在一位大佬的博客中对于匈牙利算法的一句总结:有机会就上,没有机会创造机会也要上。这里顺便向铁人王进喜致敬(丝毫没有滑稽的味道)。
这个代码是以洛谷上的二分图匹配的板子题P3386 【模板】二分图匹配为标准写的代码
#include<cstdio>
#include<cstring>
using namespace std;
int n,ans,lnk[2005],nxt[1000005],son[1000005],tot,gir[2005],m,e;
bool usd[2005];
inline void add(int x,int y){nxt[++tot]=lnk[x],son[tot]=y,lnk[x]=tot;}
inline bool fnd(int x){
for (int i=lnk[x];i;i=nxt[i]){
if (!usd[son[i]]){
usd[son[i]]=1;
if (!gir[son[i]]||fnd(gir[son[i]])){gir[son[i]]=x;return 1;}
}
}
return 0;
}
int main(){
// freopen("XYLSF.in","r",stdin);
// freopen("XYLSF.out","w",stdout);
scanf("%d%d%d",&n,&m,&e);
for (int i=1;i<=e;i++){
int x,y;scanf("%d%d",&x,&y);
if (y>m)continue;else add(x,n+y);
}
for (int i=1;i<=n;i++)memset(usd,0,sizeof(usd)),ans+=fnd(i);
printf("%d\n",ans);
return 0;
}