匈牙利算法

指派问题匈牙利算法

谁都会走 提交于 2020-01-22 15:27:58
一、问题描述 问题描述:N个人分配N项任务,一个人只能分配一项任务,一项任务只能分配给一个人,将一项任务分配给一个人是需要支付报酬,如何分配任务,保证支付的报酬总数最小。 问题数学描述:    二、实例分析---穷举法 在讲将匈牙利算法解决任务问题之前,先分析几个具体实例。 以3个工作人员和3项任务为实例,下图为薪酬图表和根据薪酬图表所得的cost矩阵。    利用最简单的方法 (穷举法) 进行求解,计算出所有分配情况的总薪酬开销,然后求最小值。 total_cost1 = 250 + 600 + 250 = 1100; x00 = 1,x11 = 1,x22 = 1; total_cost2 = 250 + 350 + 400 = 1000; x00 = 1,x12 = 1,x21 = 1; total_cost3 = 400 + 400 + 250 = 1050; x01 = 1,x10 = 1,x22 = 1; total_cost4 = 400 + 350 + 200 = 950; x01 = 1,x12 = 1,x20 = 1; //最优分配 total_cost5 = 350 + 400 + 400 = 1150; x02 = 1,x10 = 1,x21 = 1; total_cost6 = 350 + 600 + 250 = 1150; x02 = 1,x11 = 1

二分图匹配及匈牙利算法的全面讲解及python实现

。_饼干妹妹 提交于 2020-01-16 10:06:05
1 、背景 在生活中常常遇到两组元素多对多匹配而又数目有限的情况,我们需要对其进行最大匹配数的分配,使效率最大化。例如,有一组压缩气缸和一组压缩活塞,每一个型号的压缩气缸有一个固定的内径大小,每一个型号的压缩活塞可以匹配内径在一定范围内的气缸,使用匈牙利算法得到活塞和气缸对大匹配数的方案。 2 、二分图定义 二分图又称作二部图,是图论中的一种特殊模型。 设 G=(V,E) 是一个无向图,如果顶点 V 可分割为两个互不相交的子集 (A,B) ,并且图中的每条边 ( i , j) 所关联的两个顶点 i 和 j 分别属于这两个不同的顶点集 (i∈ A,j∈ B) ,则称图 G 为一个二分图。选择这样的子集中边数最大的子集称为图的最大匹配问题。 二分图匹配是很常见的算法问题,一般用匈牙利算法解决二分图最大匹配问题。 3 、匹配定义 匹配: M 是 G 的一个匹配, (M : { (x2,y4),(x3,y1),(x4,y3),(x6,y5)}) M- 交错路: p 是 G 的一条通路,如果 p 中的边为不属于 M 但属于 G 中的边与属于 M 中的边交替出现,则称 p 是一条 M- 交错路。即从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边、 ... 形成的路径。例如 :x1-y3-x2-y3 。 M- 饱和点: 对于 v ∈ V(G) ,如果 v 与 M 中的某条边关联,则称 v

完美匹配-匈牙利算法(Hungarian method Edmonds)讲解

故事扮演 提交于 2019-12-18 00:28:51
目录 匈牙利算法(Hungarian method Edmonds) 例题 代码实现 匈牙利算法(Hungarian method Edmonds) 以任意一个匹配M作为开始。(可取M=∅。) 若M已饱和X的每个顶点,停止(M为完美匹配)。否则,取X中M-不饱和顶点u,今:S<-{u},T=∅。 若N(S)=T,则停止,算法结束(无完美匹配);否则N(S)⊃T,转到下一步。 取y∈N(S)\T,若y为M-饱和的,设yz∈M,则令S=S∪(z),T=T∪{y},转步骤②;否则,y为M-不饱和的,存在M-可扩路P,令M=M△E(P),转到步骤①。 M-饱和的:边uv∈M,则称点u与v为M-饱和的。 M-不饱和的:与点w相关联的所有边都不属于M,则称点m为M-不饱和的。 N(S):点集S的邻集,图中所有与S中的点相邻接的顶点的集合。 M-交错路:p是G的一条通路,如果p中的边为属于M中的边与不属于M但属于G中的边交替出现,则称p是一条M-交错路。 M-可扩路(增广路)P:属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现, 起点与终点都是M-不饱和的 。 E(P): M-可扩路(增广路)P的边的集合。 M△E(P)=(M∪E(P))\(M∩E(P)) 由可扩路(增广路)的定义可以推出下述三个结论: (1)P的路径个数必定为奇数, 第一条边和最后一条边都不属于M 。 (2

数学:匈牙利算法

余生长醉 提交于 2019-12-13 11:12:30
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 匈牙利算法:它由匈牙利数学家Edmonds于1965年提出,因而得名。此算法的核心就是寻找增广路径,通过增广路径来求二分图最大匹配的一种算法。 通过这个图片来讲述一下。黑色代表A\B\C\D四只小狗,红色代表四种口味的骨头,每一条线表示的是小狗喜欢吃这个口味的骨头。 我们按照顺序给小狗们分配骨头,先给A分配,很明显a无人占用并且小A狗很喜欢,分配,博主最喜欢成人之美。(????) 现在给小B狗分配,小B喜欢b,前提b无人占用并且小B心仪很久,又成全一只小狗,哇哈哈~~ 轮到小C狗了,小C等了好久了,但是小C喜欢的骨头全都被占了,好可怜有木有,但是没关系,我们想办法来帮助他。如下图。 通过这张图,我们可以很清晰的知道,我们把A的先拿掉,但是还是要给找一个,不然岂不是太偏心,给A找到b,但是b被占了,同理,也先拿掉,这样A满足了,在给B继续找, 这样我们就找到c,ok大家都可以找到后备胎了,那么小C可以吃a!!!同理对d一样,但是发现如果满足d,其他的都会被破坏,综上,得到最大的匹配值为3。 匈牙利算法的流程就是上述的方案。 http://blog.csdn.net/dark_scope/article/details/8880547 这个地址有精确描述,附加代码 来源: oschina 链接: https:/

匈牙利算法

会有一股神秘感。 提交于 2019-12-13 10:37:29
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 概述 在二分图中寻找最大匹配数的算法(如对二分图不熟悉,可以看下笔者的另一篇文章 二分图/二部图检测(动图&代码实现) ),即对一侧的每一个尚未匹配的顶点,不断寻找可以增广的交替路 交替路: 匹配边和非匹配边交替出现 增广路径: 从一侧的非匹配点终止于另一个非匹配点 匈牙利算法 思路 从左侧的一个非匹配点出发 从右向左的边,永远走匹配边 终止于另一个非匹配点,则有增广路径,最大匹配数加1 补充:左侧和右侧只是一种说法,等价于一侧和另一侧 二分图寻找最大匹配数 下图是一个二分图,将会通过给这个图寻找最大匹配数,来描述匈牙利算法寻找增广交替路的思路 补充:匹配后的点置为红色,匹配边也置为红色 从顶点0出发,到达顶点4,此时顶点0和顶点4都是非匹配点,则找到一条增广交替路,最大匹配数为1 从顶点1出发,从 右->左的边只走匹配边 ,所以走1->4->0,此时来到顶点0,还可以走到顶点6,顶点6又是一个非匹配点,则找到一条增广的交替路,将该交替路中的 匹配路变为非匹配路,非匹配路变为匹配路 ,并将顶点1和顶点6置为匹配点 此时的最大匹配数为2 从顶点2出发,依次走过:2->6->0->4->1->5,找到一条新的增广交替路,再进行一次变换,并将顶点2和顶点3置为匹配点 此时的最大匹配数为3 至此,所有的顶点都匹配到了

km算法入门

≡放荡痞女 提交于 2019-12-05 00:29:21
km算法入门 https://www.cnblogs.com/logosG/p/logos.html 本文知识均由笔者自学,文章有错误之处请不吝指出。 笔者刷数模题的时候有一道题考到了“二分图最大权分配”,需要用到KM算法,但是书上对KM算法的介绍又臭又长,更何况有些同学“匈牙利算法”也没学过(由匈牙利数学家Edmonds提出),自然难以理解所谓的KM算法。本文旨在用通俗易懂的语言,向读者介绍匈牙利算法和KM算法。 一、匈牙利算法 匈牙利算法用于解决什么问题? 匈牙利算法用于解决二分图的 最大匹配 问题。 什么是二分图?我们不妨来考虑这样一个问题,在一家公司里,有员工A,B,C,有三种工作a,b,c,如果员工和工作之间有线相连,则代表员工能胜任这份工作。 如图所示,员工A能胜任a,c工作,员工B能胜任a,b,c工作,而员工C只能胜任c工作。 上图就是所谓的“二分图”(请忽略图中箭头),简单的说,上图可划分为两个集合{员工},{工作},两个集合之间的元素可以相连,同一个集合内的元素不能相连。 下面请解决这样一个问题:请给出一个方案,让尽可能多的员工有 不同 的工作做。“匈牙利算法”的出现就是为了解决这个问题。 下面给出这个问题的解决方案:(读者看到这里可能会想,解决这个问题不是很简单吗?A→a,B→b,C→c不就好了?请注意:任何算法的给出都是为了 规整化 一个问题的解决步骤

二分图匈牙利算法

匿名 (未验证) 提交于 2019-12-03 00:13:02
求二分图的算法――匈牙利 例题: https://www.luogu.org/problem/P3386 思路: 首先二分图是一个求一堆东西(例如狗),喜欢一些东西(例如肉),但是他们喜欢的肉不同,求最大限度能满足多少条狗的问题。那么我们可以画一个图,把狗放在一侧,把肉放在一侧。 如果第i只狗, 喜欢第j个肉,那么,就从i-->j连一条有向边。 然后, 我们用贪心的思想进行dfs。 我们定义choose[i]表示第i个肉被第choose[i]个狗获得。 然后我们定义一个vis数组,防止死循环。 我们枚举1 ~ n,dfs判断第i只狗能否吃到肉。 dfs中,我们枚举i所喜欢的肉,如果第j个肉没有被吃 || 吃这个肉的狗可以吃别的肉,那么就return 1(及当前狗可以吃到肉),否则return 0。 如果return 1,就ans++(及可以吃到自己喜欢的肉的狗的数量++)。 注意:每次dfs都要把vis清空。 最后答案就是ans。 代码: 1 #include < bits / stdc ++. h > 2 #define INF 0x3f3f3f3f 3 using namespace std ; 4 int n , m , edge , head [ 100001 ], vis [ 100001 ], choose [ 100001 ], num , ans ; 5

二分图匹配入门---匈牙利算法

匿名 (未验证) 提交于 2019-12-02 23:57:01
超好玩匹配 很详细的二分图 n个男孩子,m个女孩子,男孩子对女孩子有好感(匹配者与被匹配这的关系是有向图或无向图,此时为无向图,如果女孩子也有喜欢的男孩子的话,就是有有向图) 进行男孩子匹配 可以用二维数组来构建图的关系,line[i][j]的权值表示I对j的联通,现在是1表示i对j存在好感,当出现有权值时就不一样了. 数组girl[]表示被匹配者匹配的是谁 used[]是一个动态的清零操作数组,在每次匹配的时候记录是否被匹配 HDU2063裸匹配,匈牙利算法即可 //有向图二分最大匹配---匈牙利算法 //一个图有两个子图,一个m个结点的子图,一个n个结点的子图,前者是主动匹配,后者是用来被匹配的 #include <iostream> #include <cstdio> #include <cstring> using namespace std ; const int N = 505 ; int line [ N ][ N ]; int girl [ N ]; // int used [ N ]; //被匹配这是否被匹配,每次匹配都要进行清零操作,因为要实现腾出给其他女孩子用 int k , m , n ; //可能的组合数目,女生人数,男生人数 bool find ( int x ){ for ( int i = 1 ; i <= n ; i ++){ /

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

Deadly 提交于 2019-12-02 20:21:33
二分图也是二部图,即可以将一个图分为两部分。 用男女举例,男生与女生有暧昧关系,同性之间是不存在暧昧的 (同性才是真爱,异性只为传宗接代) ,则他们之间存在一条边,那么我们可以将男生,女生分开,男生在左边,女生在右边 我们可以发现在左边的男生是没有边相连的,右边的女生也是,他们只与对面的异性存在边,那么这就是一个二分图。 至于匹配问题也很好理解,这里可以看成夫妻关系,一个男生可以有几个暧昧的异性,但是只有一位妻子,女生也是如此;一对夫妻即一组匹配 那么在给出的一个二分图中,求最大匹配就是最多存在几对夫妻。 求二分图最大匹配这里介绍匈牙利算法: 强推这位博主讲的匈牙利 : https://blog.csdn.net/dark_scope/article/details/8880547 给出一道洛谷的模板题: P3386 【模板】二分图匹配 这里给出我的代码: 1 /* 2 二分图最大匹配模板 3 czq 4 */ 5 6 #include <cstdio> 7 #include <cstring> 8 #include <iostream> 9 using namespace std; 10 const int N = 1e3 + 10; 11 12 int n, m, e; 13 int edges[N][N]; 14 int vis[N], rec[N]; 15 /

匈牙利算法

无人久伴 提交于 2019-11-29 14:08:05
简单地说,就是一张图里的所有点可以分为两组(如上图),并且每条边都跨越两组。这样的图就是二分图。 一个图为二分图仅当: 没有奇数圈; 点色数为 2。 交替路 (也叫交错路):从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边……形成的路径叫交替路。 增广路 :从一个未匹配点出发,走交替路,以另一个未匹配点为结尾(出发的点不算),则这条交替路称为增广路 增广路定理: 任意一个非最大匹配的匹配一定存在增广路。 我们可以一直找增广路,不断交换匹配。根据增广路定理, 如果找不到了,就说明已经达到最大匹配。 #include <iostream> #include <cstring> using namespace std; int map[100][100]; int ans=0; int visit[100],link[100]; int n,m; bool dfs(int x) { for(int i=1;i<=n;i++) { if(!visit[i]&&map[x][i]) { visit[i]=1; if(!link[i]||dfs(link[i])) { link[i]=x; return 1; } } } return 0; } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; map