关于匈牙利算法的两三事(新手向)

  这是一篇简单的匈牙利算法的理解篇,首先匈牙利算法的名字听起来就和匈牙利牛肉饭一样让人产生食欲(?)233。

  好的接下来我们开始正式带大家了解什么叫匈牙利算法。

  那么要了解算法的基本原理,我们先看一张图

在这张图里,我们可以清楚的看出图上的点被我们分成了两种,一种是数字,另一种是字母,并且数字与数字、字母与字母之间是没有互相连接的边的,这种点被划为两种、且每种之间没有连边的图就叫做二分图,而我们的匈牙利算法就是用来处理二分图匹配的。

  什么叫二分图匹配捏,很简单,我们从这张图中选出一些边,举个例子,我们选出1——C,2——A,4——D这三条边,使得每条边对应左右两边各一个点,且对于每个点来说,边唯一。

  而对于匈牙利算法来说,它求的是二分图最大匹配,什么叫最大匹配捏,就是说在二分图中选择尽可能多的边,使它们遵从二分图匹配的规则,如果我们选择的边数为全图点数除以2的话,则叫做完全匹配。

  那么匈牙利算法具体怎么实现捏?具体如以下图示

首先我们找到左边的1,从1出发选择1能连到的第一条边为1——C(上图中标红的边)

具体为我们从左边第一个没有连到边的点(如原始图所示为1)开始搜索,找到第一个可以连到的点C,然后选择连接两个点,记录连接点C的是1。

接下来找到第二个点2,同样连接 2 和 与2连接的第一个没有被连接过的点(如上图所示为A),记录连接点A的是2。

  重点!!!!!

  接下来就是匈牙利算法的精髓所在,因为从3开始连接的时候我们就开始慌了,唯一和3连接的点A已经被连过了,那么接下来就是展现匈牙利算法的威力的时刻啦哈哈哈哈哈哈哈(蜜汁笑声)

  那么我们要做的是用深度优先搜索找出首先找出与当前失匹配点3所能联通的点(上图青色边为我们深搜的过程路径),那么当前所找到的就为A,因为A已经被连接,所以我们可以直接找到连接A的是2,然后继续深搜。

  然后继续从2开始搜索,找一条能与2连接,并且不是当前来的路径(2——A)的另一条路径(根据匈牙利算法,如果这里找不到就返回上一层,知道搜索完深度优先搜索开始节点3的每一条边,如果都找不到就判断这次算法执行没有更优结果),那么显然的,我们找到了C这个点。

同样的,我们之前记录过连接C的节点(也就是1),那么继续以1开始搜索与1连接,并且不是1——C这条路径的另一条路径,

  显然的,找到1——E这条路径,然后对点E进行判断。

  这时我们发现E是没有其他路径与其他点连接的,那么这时我们开始return,那么看,此时图中所有标为青色的边是我们的搜索路径,那么我们在return时要做的事情就是:把所有{只标青而没有变红的边}变为新的连接边,而吧所有{又标红又标青的边}取消连接.

  那么这时图就变成

  那么对于当前情况,我们就相当于完成了局部最优匹配,然后接下来就是继续按照这种方法完成全图最优匹配就好了。

  那么完成图就为

这时我们就求出了二分图最大匹配

(PS写在最后,我们是要记录:{每次连接边后,成功连接右边某个点的左边点的位置},同时如果我们做的找到环的话就只能回到上一层,所以要记录{哪些点在当前搜索中用到},这样下次搜索就不会死循环)

附上一道水题,codevs1022  http://codevs.cn/problem/1022/

那么这道题里面,我们把所有格子按国际象棋棋盘的染色法进行染色,使得与黑相邻的所有点都为白色,与白色相邻的点都为黑色,然后把所有没有被水淹的格子按黑白做一个二分图,那么每个格子一开始的路径就为与它四周不出界且没有被水淹的格子连接所产生的路径,然后单纯的做匈牙利算法就好了呀。

然后贴出代码(PS蜜汁变量名和谐修改)

 1 #include<stdio.h>
 2 int xx[4]={0,1,0,-1},yy[4]={1,0,-1,0};
 3 bool usd[110][110],map[110][110],wat[110][110];
 4 int n,m,k,from[110][110][3],ans;
 5 bool find(int x,int y)
 6 {
 7     int k;
 8     for(k=0;k<4;k++)
 9     {
10         int xi=x+xx[k],yi=y+yy[k];
11         if(xi<1||xi>n||yi<1||yi>m)continue;
12         if(!map[xi][yi]&&!usd[xi][yi]&&!wat[xi][yi])
13         {
14             usd[xi][yi]=true;
15             if(!from[xi][yi][0]||find(from[xi][yi][0],from[xi][yi][1]))
16             {
17                 from[xi][yi][0]=x;
18                 from[xi][yi][1]=y;
19                 return true;
20             }
21         }
22     }
23     return false;
24 }
25 int main()
26 {
27     int a,b;
28     scanf("%d%d%d",&n,&m,&k);
29     for(int i=1;i<=k;i++)
30     {
31         scanf("%d%d",&a,&b);
32         wat[a][b]=true;
33     }
34     for(int i=1;i<=n;i++)
35         for(int j=1;j<=m;j++)
36         {
37             if(i%2==0&&j%2==0)map[i][j]=true;
38             if(i%2&&j%2)map[i][j]=true;
39         }
40     for(int i=1;i<=n;i++)
41     {
42         for(int j=1;j<=m;j++)
43         {
44             if(!wat[i][j]&&map[i][j])
45             {
46                 for(int ii=1;ii<=n;ii++)
47                     for(int jj=1;jj<=m;jj++)
48                     usd[ii][jj]=false;
49                 if(find(i,j))
50                 {
51                     ans++;
52                 }
53             }
54         }
55     }
56     printf("%d",ans);
57     return 0;
58 }
时间: 2024-08-08 05:35:18

关于匈牙利算法的两三事(新手向)的相关文章

二分图最大匹配|UOJ#78|匈牙利算法|边表|Elena

#78. 二分图最大匹配 从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生.编号分别为 1,-,nl1,-,nl 和 1,-,nr1,-,nr. 有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为配偶. 请问这个班级里最多产生多少对配偶? 输入格式 第一行三个正整数,nl,nr,mnl,nr,m. 接下来 mm 行,每行两个整数 v,uv,u 表示第 vv 个男生和第 uu 个女生愿意结为配偶.保证 1≤v≤nl1≤v≤nl,1≤u≤nr1≤u≤nr,保证同一个条件

匈牙利算法

(一)首先明确匈牙利算法是干嘛滴? 匈牙利算法是解决二部图最大匹配问题滴. (二)算法的核心思想:不断寻找增广路径,每找到一条增广路径,就通过异或操作使匹配边数加一,直到找不到增广路径,算法结束. (三)算法的基本步骤: (1)任取二部图G(X,Y)的匹配M,若M饱和X,则停止.若M不能饱和X,则取X的未标记的M非饱和点x.(标记的点表示经过此点不存在增广路)令S={x},T= ?.(T集合中的点表示N(S)中已经加入增广路的点)(当不存非饱和点或者所有非饱和点都被标记,算法结束) (2)若N(

匈牙利算法dfs模板 [二分图][二分图最大匹配]

最近学了二分图最大匹配,bfs模板却死活打不出来?我可能学了假的bfs 于是用到了dfs模板 寻找二分图最大匹配的算法是匈牙利算法 匈牙利算法的主要程序是寻找增广路 寻找增光路是过程是:从一个未经配对的点出发,历经未配边.匹配边.未配边.匹配边.未配边....最终到达一个未配点的过程,只要把路径中的未配边和匹配边的“身份”对调,匹配就加一了.这就是一个寻找增广路的过程,通过不断寻找增广路,可以找到最大的匹配. 1 #include<cstdio> 2 #include<cstring&g

【codevs】1022覆盖(匈牙利算法)

嗯,先上题目描述... 此题接近裸的匈牙利算法,将陆地和其四周是陆地的点连一条边,这样就有了一个无向图. 接着就是从第一个点出发枚举未被标记的点,标记与其对应的另一个点(因为是1*2的长方形). 开了一个四维数组e[x1][y1][x2][y2],若为零代表点(x1,y1)与(x2,y2)不连通. match[x1][y1][1]放与点(x1,y1)配对的另一个点的x,match[x1][y1][2]放与点(x1,y1)配对点的y. 还有就是更改的时候记得双向更改,因为是无向图啊. 然后就跑df

FOJ 2232 匈牙利算法找二分图最大匹配

题目链接 简单理解匈牙利算法 简单理解二分图 尽量让每一个随从击败一个对手且随从全部存活,关键是为每一个随从找对手(递归过程),"腾". #include<iostream> #include<cstdio> #include<cstring> using namespace std; int used[110]; int g[110][110]; //建立随从和对手的对战关系 int ee[110]; int n; struct people{ i

匈牙利算法——S.B.S.

匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名.匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法. -------等等,看得头大?那么请看下面的版本: 通过数代人的努力,你终于赶上了剩男剩女的大潮,假设你是一位光荣的新世纪媒人,在你的手上有N个剩男,M个剩女,每个人都可能对多名异性有好感(-_-||暂时不考虑特殊的性取向),如果一对男女互有好感,那么你就可以把这一对撮合在一起,现在

UVALive5874 - Social Holidaying-二分图匹配/匈牙利算法

有n个家庭,m个房间,一个房间只能两个家庭住.求最大匹配. 比较标准的二分图问题.先初始化把可能的家庭建边,然后跑一边匈牙利算法. 最后的答案是最大匹配数/2,因为建图时有重复. #include <cstdio> #include <algorithm> #include <cstring> #include <map> using namespace std; const int MAXN = 410; int uN,vN; int g[MAXN][MA

棋盘覆盖及匈牙利算法

题目描述 Description 给出一张n*n(n<=100)的国际象棋棋盘,其中被删除了一些点,问可以使用多少1*2的多米诺骨牌进行掩盖. 输入描述 Input Description 第一行为n,m(表示有m个删除的格子)第二行到m+1行为x,y,分别表示删除格子所在的位置x为第x行y为第y列 输出描述 Output Description 一个数,即最大覆盖格数 样例输入 Sample Input 8 0 样例输出 Sample Output 32 数据范围及提示 Data Size &am

数学:匈牙利算法

匈牙利算法:它由匈牙利数学家Edmonds于1965年提出,因而得名.此算法的核心就是寻找增广路径,通过增广路径来求二分图最大匹配的一种算法. 通过这个图片来讲述一下.黑色代表A\B\C\D四只小狗,红色代表四种口味的骨头,每一条线表示的是小狗喜欢吃这个口味的骨头. 我们按照顺序给小狗们分配骨头,先给A分配,很明显a无人占用并且小A狗很喜欢,分配,博主最喜欢成人之美.(????) 现在给小B狗分配,小B喜欢b,前提b无人占用并且小B心仪很久,又成全一只小狗,哇哈哈~~ 轮到小C狗了,小C等了好久