浅谈算法_二分图匹配

来源:互联网 发布:福岛核电站事故 知乎 编辑:程序博客网 时间:2024/06/04 23:29

浅谈算法_二分图匹配

定义

二分图

简单来说,如果图中点可以被分为两组,并且使得所有边都跨越组的边界,则这就是一个二分图。准确地说:把一个图的顶点划分为两个不相交集U和V,使得每一条边都分别连接U,V中的顶点。如果存在这样的划分,则此图为一个二分图。二分图的一个等价定义是:不含有「含奇数条边的环」的图。图 1 是一个二分图。

匹配

在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。

算法大致流程

有一个图:
这里写图片描述
每一条线都代表一条边,每连一条边都表示一次匹配,现在我们想让左边匹配到的点最多。
那么,我们考虑,先给第一个点连边,用贪心的策略,使能匹配到的点最多。
首先:
这里写图片描述
我们用左边的第一个点连向了右边的第一个点(左边第一个点的第一条边)。
接着开始匹配第二个点:
这里写图片描述
发现与第一个点重合了,就往回找第一个点有没有其他连边,发现第一个点与右边第而个点有连边,于是我们更改它的连边(递归回去):
这里写图片描述
发现两个都可以,便继续往下做:
这里写图片描述
又发现有边已经连了,再次回去更改连边:
这里写图片描述
发现又被连了,便再回去改第二个点的匹配:
这里写图片描述
发现没有被匹配到,皆大欢喜。
继续做最后一个点,只有一条边,连上就好了:
这里写图片描述
至此匹配过程完成!
更有趣的讲解:
http://blog.csdn.net/dark_scope/article/details/8880547

主要代码

        link:array[0..10000]of longint;    mark:array[0..10000]of boolean;    map:array[0..100,0..1000]of boolean;    i,s,n,m,t,x,y:longint;function find(t:longint):boolean;var        i,q:longint;begin        for i:=1 to m do                if (not mark[i])and(map[t,i]) then                begin                        q:=link[i];                        link[i]:=t;                        mark[i]:=true;                        if (q=0)or(find(q)) then                                exit(true);                        link[i]:=q;                end;        exit(false);end;begin        readln(n,m,t);    for i:=1 to t do    begin            readln(x,y);        map[x,y]:=true;    end;        fillchar(link,sizeof(link),0);        s:=0;        for i:=1 to n do        begin                fillchar(mark,sizeof(mark),0);                if find(i) then                        inc(s);        end;    writeln(s);end.

习题

有兴趣的可以做做这几题:
【东莞市选2008】导弹:http://172.16.0.132/senior/#main/show/1015
【NOIP2013模拟联考3】沙耶的玩偶(doll):http://172.16.0.132/senior/#contest/show/2100/2

原创粉丝点击