二分图匹配
图匹配总结二分图匹配
序言:回忆起最初学习图匹配算法的艰辛与困惑,苦中有乐,但很多时间都浪费在了资料的寻找与甄别上。
因此,在对自己做一次知识总结的同时,整理与记录下了这些文字,希望能够给大家带来一定的帮助。
目录:第一部分:二分图的最大匹配第二部分:五种方式,两类构图第三部分:二分图匹配算法总结第四部分:二分图的最优权值匹配第五部分:一般图的最大匹配第六部分:图匹配题目列表符号说明:N,V:点数E:边数u,v,i,j:节点的标号INF:正无穷大-INF:负无穷大名词说明:时间复杂度:算法的理论时间上界时间效率:实际中算法运行的平均时间效率引用说明:文中参考了一些来源于网络的资料,也有原文全段引用的部分。
在这些资料被n+1次转载后,我已无法获知所有原作者的信息。
在此,对所有前辈们表示真诚的歉意和诚挚的敬意。
特别感谢Amber大神犀利的代码。
作者:Snow_storm正文:第一部分:二分图匹配有这么两个奇怪的工厂:工厂X只生产杯具,工厂Y只生产洗具。
最近,两个工厂决定将产品实行打包策略:即一个杯具搭配上一个洗具。
但由于杯具和洗具的形状和功能各不相同,对于某个类别的杯具来说,只能搭配某些类型的洗具。
现在,两个工厂的厂长大人想知道最多能成功的搭配多少对杯具与洗具。
类似于上面例子中提到的搭配问题,在图论中的有规范的名称:匹配。
注意到,上面的例子中涉及到的物品只有两类(杯具与洗具),且问题只涉及杯具与洗具的匹配,我们把这种只涉及一种关系的匹配问题称为二分匹配问题。
现在,让我们理清一些概念。
二分图:若图G中的点可以分为X和Y两部分,且每部分内部无任何边相连,则称图G为二分图。
匹配:无公共点的边集合(可以想象一下结婚这个词汇)。
匹配数:边集中边的个数最大匹配:匹配数最大的匹配。
如图1-1,展示的就是一个二分图:粗体线表示该二分图的一种匹配方式,不难发现,此时的匹配已经是最大匹配。
图 1-1如何能得到一个二分图的最大匹配?运用简单的枚举:找出全部匹配,然后保留匹配数最多的。
图论:二分图多重匹配
图论:⼆分图多重匹配使⽤最⼤流和费⽤流解决⼆分图的多重匹配之前编辑的忘存了好⽓啊。
本来打算学完⼆分图的乱七⼋糟的匹配之后再去接触⽹络流的,提前撞到了之前我们说的⼆分图最⼤匹配和⼆分图最⼤权匹配有⼀个特点,那就是没个点只能与⼀条边相匹配如果规定⼀个点要与L条边相匹配,这样的问题就是⼆分图的多重匹配问题然后根据边是否带权重,⼜可以分为⼆分图最⼤多重匹配和⼆分图最⼤权多重匹配(⼆分图多重最佳完美匹配)⾸先给出⼆分图多重最⼤匹配的做法:在原图上建⽴源点S和汇点T,S向每个X⽅点连⼀条容量为该X⽅点L值的边,每个Y⽅点向T连⼀条容量为该Y⽅点L值的边原来⼆分图中各边在新的⽹络中仍存在,容量为1(若该边可以使⽤多次则容量⼤于1),求该⽹络的最⼤流,就是该⼆分图多重最⼤匹配的值然后给出⼆分图多重最优匹配(⼆分图多重最⼤权匹配)的做法:在原图上建⽴源点S和汇点T,S向每个X⽅点连⼀条容量为该X⽅点L值、费⽤为0的边,每个Y⽅点向T连⼀条容量为该Y⽅点L值、费⽤为0的边原来⼆分图中各边在新的⽹络中仍存在,容量为1(若该边可以使⽤多次则容量⼤于1),费⽤为该边的权值。
求该⽹络的最⼤费⽤最⼤流,就是该⼆分图多重最优匹配的值这道题⾥⾯,⼀共有X⽅点这么多的电影,每个电影需要拍摄多少天就是对应的X⽅点L值,然后每⼀天是⼀个Y⽅点,由于每⼀天只能拍摄⼀部电影,所有Y⽅点的L值均为1下⾯介绍⼀下实现:int n,sum,cnt,ans;int g[maxn],cur[maxn];int str[25][10];struct Edge{int u,v,next,cap,flow;}e[maxm];这⾥⾯的cur数组是g数组的临时数组str⽤来保存每⼀个电影可以在哪⼀天拍摄Edge是⽹络流图⾥⾯的边void addedge(int u,int v,int c){e[++cnt].u=u;e[cnt].v=v;e[cnt].cap=c;e[cnt].flow=0;e[cnt].next=g[u];g[u]=cnt;e[++cnt].u=v;e[cnt].v=u;e[cnt].cap=0;e[cnt].flow=0;e[cnt].next=g[v];g[v]=cnt;}建图的时候,注意怎么赋值的接下来根据题意建图:for(int i=1;i<=n;i++){for(int j=1;j<=7;j++)scanf("%d",&str[i][j]);scanf("%d%d",&d,&w);sum+=d;addedge(0,i,d); //容量为需要多少天for(int j=1;j<=7;j++)for(int k=0;k<w;k++)if(str[i][j]) addedge(i,20+k*7+j,1);}for(int i=21;i<=370;i++) addedge(i,371,1);ans=maxflow(0,371);0为源点,371为汇点sum最后进⾏⼀个统计,和源点出发的最⼤流量进⾏⽐较,如果相等,说明电影排的开然后是求最⼤流的⼀个板⼦int maxflow(int st,int ed){int flowsum=0;while(bfs(st,ed)){memcpy(cur,g,sizeof(g));flowsum+=dfs(st,ed,INF);//cout<<"#"<<flowsum<<" ";}return flowsum;}具体的DFS和BFS这⾥不作为重点,以后再说下⾯给出完整的实现:1 #include<cstdio>2 #include<cstring>3 #include<algorithm>4using namespace std;5const int INF=1000000000;6const int maxn=1005;7const int maxm=20005;8int n,sum,cnt,ans;9int g[maxn],cur[maxn];10int str[25][10];11struct Edge{int u,v,next,cap,flow;}e[maxm];12void addedge(int u,int v,int c)13 {14 e[++cnt].u=u;e[cnt].v=v;e[cnt].cap=c;15 e[cnt].flow=0;e[cnt].next=g[u];g[u]=cnt;1617 e[++cnt].u=v;e[cnt].v=u;e[cnt].cap=0;18 e[cnt].flow=0;e[cnt].next=g[v];g[v]=cnt;19 }20int q[maxn],vis[maxn],d[maxn];21bool bfs(int st,int ed)22 {23 memset(q,0,sizeof(q));24 memset(vis,0,sizeof(vis));25 memset(d,-1,sizeof(d));26 vis[st]=1;d[st]=0;27int h=0,t=1;28 q[t]=st;29while(h!=t)30 {31 h=h%maxn+1;32int u=q[h];33for(int tmp=g[u];tmp;tmp=e[tmp].next)34 {35if(!vis[e[tmp].v]&&e[tmp].cap>e[tmp].flow)36 {37 vis[e[tmp].v]=1;38 d[e[tmp].v]=d[u]+1;39if(e[tmp].v==ed) return true;40 t=t%maxn+1;41 q[t]=e[tmp].v;42 }43 }44 }45return false;46 }47int getpair(int x)48 {49if(x%2==0)50return x-1;51else return x+1;52 }53int dfs(int x,int ed,int a)54 {55if(x==ed||a==0) return a;56int flow=0,f;57for(int tmp=cur[x];tmp;tmp=e[tmp].next)58 {59if(d[e[tmp].v]==d[x]+1&&(f=dfs(e[tmp].v,ed,min(a,e[tmp].cap-e[tmp].flow)))>0)60 {61 e[tmp].flow+=f;62 e[getpair(tmp)].flow-=f;63 a-=f;64 flow+=f;65if(a==0) break;66 }67 }68return flow;69 }70int maxflow(int st,int ed)71 {72int flowsum=0;73while(bfs(st,ed))74 {75 memcpy(cur,g,sizeof(g));76 flowsum+=dfs(st,ed,INF);77//cout<<"#"<<flowsum<<" ";78 }79return flowsum;8081 }82void init()83 {84 sum=cnt=0;85 memset(g,0,sizeof(g));86 }87int main()88 {89int T,d,w;90 scanf("%d",&T);91while(T--)92 {93 init();94 scanf("%d",&n);95for(int i=1;i<=n;i++)96 {97for(int j=1;j<=7;j++)98 scanf("%d",&str[i][j]);99 scanf("%d%d",&d,&w);100 sum+=d;101 addedge(0,i,d); //容量为需要多少天102for(int j=1;j<=7;j++)103for(int k=0;k<w;k++)104if(str[i][j]) addedge(i,20+k*7+j,1);105 }106for(int i=21;i<=370;i++) addedge(i,371,1);107 ans=maxflow(0,371);108if(ans==sum) printf("Yes\n");109else printf("No\n");110 }111return0;112 }据说这是典型的最⼤流题⽬,然⽽为了强⾏安利⼀波⼆分图的多重匹配,就不说成那个了。
二分图匹配(匈牙利算法)
设G=(V,{R})是一个无向图。
如顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属两个不同的子集。
则称图G为二分图。
v给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
v选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)v如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。
最大匹配在实际中有广泛的用处,求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。
但是这个算法的复杂度为边数的指数级函数。
因此,需要寻求一种更加高效的算法。
匈牙利算法是求解最大匹配的有效算法,该算法用到了增广路的定义(也称增广轨或交错轨):若P是图G中一条连通两个未匹配顶点的路径,并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M 的一条增广路径。
由增广路径的定义可以推出下述三个结论:v 1. P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
v 2. P经过取反操作(即非M中的边变为M中的边,原来M中的边去掉)可以得到一个更大的匹配M’。
v 3. M为G的最大匹配当且仅当不存在相对于M的增广路径。
从而可以得到求解最大匹配的匈牙利算法:v(1)置M为空v(2)找出一条增广路径P,通过取反操作获得更大的匹配M’代替Mv(3)重复(2)操作直到找不出增广路径为止根据该算法,我选用dfs (深度优先搜索)实现。
程序清单如下:int match[i] //存储集合m中的节点i在集合n中的匹配节点,初值为-1。
int n,m,match[100]; //二分图的两个集合分别含有n和m个元素。
bool visit[100],map[100][100]; //map存储邻接矩阵。
bool dfs(int k){int t;for(int i = 0; i < m; i++)if(map[k][i] && !visit[i]){visit[i] = true;t = match[i];match[i] = k; //路径取反操作。
二分图最大匹配问题贪心算法
二分图的最大匹配
e.g.飞行员分成两部分,一部分是正驾驶员,一部分是副驾驶员。显然,如何搭配正副驾驶员才能使出航飞机最多的问题可以归结为一个二分图上的最大匹配问题。
常用算法
网络流算法(编程复杂,小题大做) 匈牙利算法(理解困难,实现简单) 以上这些我都不会怎么办?
二分图的基本概念
二分图是一类特殊的图结构 二分图是这样一种图:G的顶点集合V分成两部分X与Y,G中每条边的两个端点一定是一个属于X而另一个属于Y。
匹配的基本概念
设G=[V,E]是一个无向图,M属于E是G的若干条边的集合,如果M中的任意两条边都没有公共的端点,就称M是一个匹配。
最大匹配的基本概念
注意
以上所述的贪心算法仅适用于二分图的最大匹配问题,最佳匹配问题是不适用的。 本人尚未见到有人能够对此算法给出严格的证明,但是网上确实也有不少人有用此算法过全点的经历。 总之,请各位慎重使用! (:以下附例题的主程序的代码
主程序代码
贪心算法
下面,我们引进一种能够完美解排
一个重要的会议由A公司的M位代表和B公司的N位代表参加(M,N≤1000,代表用1,2,……,M和1,2,……,N表示)。他们被预先分成K(K≤60000)组进行谈判。每组两个人分别来自A公司和B公司。每个参加会议的代表都至少参加了一组谈判。会议为每一个代表都准备了一个房间。技术人员将会在一些房间之间连上直通电话,一个代表至少要和他的一个谈判对手直接联络。连接一个直通电话的价格是常数。技术人员要用尽量少的花费满足会议的要求。
贪心算法
接着,我们将u,v两点都进行删除操作。 (当u的出边所对的点都已被访问,那么就找不到满足条件的v,因此只对u进行操作) 所谓删除操作,在这里,删除s,其实就是将s的所有出边所对的点t的出度都减一。 (因为要删除点s,即(s,t)也被删除,即(t,s)也要被删除,所以t的出度要减一)
算法合集之《浅析二分图匹配在信息学竞赛中的应用》
05 二分图匹配的实践案例
最大二分匹配问题的应用案例
最大二分匹配问题
在二分图中寻找最大的匹配数,使得每条边只被匹配一次。
应用案例
社交网络中的好友推荐。通过最大二分匹配算法,可以找到社 交网络中最多共同好友的两个人,从而推荐他们成为好友。
算法实现
使用匈牙利算法或Kuhn-Munkres算法求解最大二分匹配 问题。
剪枝策略
剪枝条件
在匹配过程中,根据一定的条件判断是否可以剪去当前分支 ,以减少不必要的计算量。
剪枝操作
在匹配过程中,根据剪枝条件进行剪枝操作,避免匹配到不 可能的解。
并查集策略
并查集初始化
在处理二分图匹配问题之前,将图中 的节点按照所属类别进行初始化。
并查集合并操作
在匹配过程中,根据并查集的合并操 作快速判断一条边是否存在于图中, 提高匹配效率。
算法实现
使用匈牙利算法、Kuhn-Munkres算法等经典算法,通过寻找 增广路径和增广回溯的方式求解最大二分匹配。
应用场景
在信息学竞赛中,最大二分匹配问题常用于解决诸如排班、分配 等问题,具有广泛的实际应用价值。
二分图的顶点覆盖问题
二分图的顶点覆盖问题
01
在二分图中寻找最小的顶点集合,使得该集合覆盖所
算法合集之《浅析二分图匹 配在信息学竞赛中的应用》
目录
Contents
• 二分图匹配概述 • 二分图匹配的算法 • 二分图匹配在信息学竞赛中的应用 • 二分图匹配的优化策略 • 二分图匹配的实践案例
01 二分图匹配概述
二分图匹配的定义
二分图匹配是指将一个二分图中的顶 点划分为两个不相交的子集,使得每 个子集中的顶点之间没有边相连,而 两个子集之间通过边相连。
匈牙利匹配算法的原理
匈牙利匹配算法的原理匈牙利匹配算法(也被称为二分图匹配算法或者Kuhn-Munkres算法)是用于解决二分图最大匹配问题的经典算法。
该算法由匈牙利数学家Dénes Kőnig于1931年提出,并由James Munkres在1957年进行改进。
该算法的时间复杂度为O(V^3),其中V是图的顶点数。
匹配问题定义:给定一个二分图G=(X,Y,E),X和Y分别代表两个不相交的顶点集合,E表示连接X和Y的边集合。
图中的匹配是指一个边的集合M,其中任意两条边没有公共的顶点。
匹配的相关概念:1.可增广路径:在一个匹配中找到一条没有被占用的边,通过这条边可以将匹配中的边个数增加一个,即将不在匹配中的边添加进去。
2. 增广路径:一个可增广路径是一个交替序列P=v0e1v1e2v2...ekvk,其中v0属于X且不在匹配中,v1v2...vk属于Y且在匹配中,e1e2...ek在原图中的边。
3.增广轨:一个交替序列形如V0E1V1E2...EkVk,其中V0属于X且不在匹配中,V1V2...Vk属于Y且在匹配中,E1E2...Ek在原图中的边。
增广轨是一条路径的特例,它是一条从X到Y的交替序列。
1.初始时,所有的边都不在匹配中。
2.在X中选择一个点v0,如果v0已经在匹配中,则找到与v0相连的在Y中的顶点v1、如果v1不在匹配中,则(v0,v1)是可增广路径的第一条边。
3. 如果v1在匹配中,则找到与v1相连的在X中的顶点v2,判断v2是否在匹配中。
依此类推,直到找到一个不在匹配中的点vn。
4.此时,如果n是奇数,则(n-1)条边在匹配中,这意味着我们找到了一条增广路径。
如果n是偶数,则(n-1)条边在匹配中,需要进行进一步的处理。
5.如果n是偶数,则将匹配中的边和非匹配中的边进行颠倒,得到一个新的匹配。
6.对于颠倒后的匹配,我们再次从第2步开始,继续寻找增广路径。
7.重复步骤2到步骤6,直到找不到可增广路径为止,此时我们得到了最大匹配。
[算法]二分图最大匹配
[算法]⼆分图最⼤匹配前⾔具体什么是⼆分图,如何判定,可以参考。
定义简单来说,就是⼆分图中有满⾜任意两条边没有相同的点的边的集合,称为⼀组匹配,⽽边数最多的⼀组匹配称为该⼆分图的最⼤匹配。
在⼀组匹配中,属于这组边的称为匹配边,不属于的称为⾮匹配边,属于这组匹配的点称为匹配点,不属于的称为⾮匹配点。
匈⽛利算法⼜称增⼴路算法。
对于⼀组匹配 \(M\) ,若存在⼀条路径连接两个⾮匹配点,且使得匹配边与⾮匹配边交替出现,则称这条路径为增⼴路。
如上图,已匹配的边为红⾊,未匹配的边为绿⾊,则可以找到⼀组增⼴路 \(8\) ~ \(2\) ~ \(7\) ~ \(4\) 。
不难发现增⼴路具有以下特点:以⾮匹配边开始,在以⾮匹配边结尾,那么长度必为奇数。
路径上第⼀条边因为第⼀个点为奇数,则该路径上的第⼀个点为⾮匹配边,按照匹配边与⾮匹配边交替出现的性质可以得出,该路径的第奇数条边必为⾮匹配边,已经匹配的边必为第偶数条边,则有⾮匹配边的边数⽐匹配边的边数多⼀。
最⼤匹配中不会有增⼴路。
证明:假设最⼤匹配中存在增⼴路,则可以将增⼴路中的所有边的状态取反(即把⾮匹配边转换为匹配边,将匹配边转换为⾮匹配边),得到另⼀组匹配,⽽这组匹配的匹配边肯定会⽐之前的⼀组匹配的边数多⼀,则之前的这组匹配就不是最⼤匹配,与假设⽭盾,证毕。
在⼀张⼆分图中,若最⼤匹配为 \(S\) ,当且仅当 \(S\) 中不存在增⼴路。
其确性基于 \(hall\) 定理,⽐较复杂就不在详讲,主要讲找⼆分图最⼤匹配的⽅法。
⼤体思想就是枚举左部点,找到增⼴路后将这条路上的所有边的状态取反,得到边数更⼤的⼀组匹配。
在匹配过程中,有两种情况会改变当前左部点 \(u\) 的匹配情况。
1. 与之对应的右部点 \(v\) 是⾮匹配点,则可以将其的连边变为匹配边。
2. 与之对应的右部点 \(v\) 是匹配点,但与 \(v\) 已经匹配的点 \(u'\) 可以找到另⼀个未匹配的右部点 \(v'\) ,则 \(u\) ~ \(v\) ~ \(u'\) ~ \(v'\) 为⼀条增⼴路,则将其状态取反。
二分图匹配(匈牙利算法)
KM算法
对于任意的G和M,可行顶标都是存在的: l(x) = maxw(x,y) l(y) = 0 欲求完全二分图的最佳匹配,只要用匈牙利算法求 其相等子图的完备匹配;问题是当标号之后的Gl无 完备匹配时怎么办?1957年(居然比匈牙利算法 早???),Kuhn和Munkras给出了一个解决该问 题的有效算法,用逐次修改可行顶标l(v)的办法使对 应的相等子图之最大匹配逐次增广,最后出现完备 匹配.
例题3 打猎 猎人要在n*n的格子里打鸟,他可以在某一行 中打一枪,这样此行中的所有鸟都被打掉, 也可以在某一列中打,这样此列中的所有鸟 都打掉.问至少打几枪,才能打光所有的鸟? 建图:二分图的X部为每一行,Y部为每一列, 如果(i,j)有一只鸟,那么连接X部的i与Y部的j. 该二分图的最大匹配数则是最少要打的枪数.
1 2 3 4 5
1 2 5 3 4
1
2
3
4
由于每条边表示一个空地,有冲 突的空地之间必有公共顶点,所 以问题转化为二部图的最大匹配 问题.
1 2Leabharlann 34例题1 Place the Robots(ZOJ) 小结
比较前面的两个模型:模型一过于简单,没有给问 题的求解带来任何便利;模型二则充分抓住了问题的内 在联系,巧妙地建立了二部图模型.为什么会产生这种 截然不同的结果呢?其一是由于对问题分析的角度不同: 模型一以空地为点,模型二以空地为边;其二是由于对 原型中要素的选取有差异:模型一对要素的选取不充分, 模型二则保留了原型中"棋盘"这个重要的性质.由此 可见,对要素的选取,是图论建模中至关重要的一步.
例题4 最小路径覆盖 一个不含圈的有向图G中,G的一个路径覆盖 是一个其结点不相交的路径集合P,图中的每 一个结点仅包含于P中的某一条路径.路径可 以从任意结点开始和结束,且长度也为任意 值,包括0.请你求任意一个不含圈的有向图 G的最小路径覆盖数. 理清一个关系:最小路径覆盖数=G的定点 数-最小路径覆盖中的边数
二分图的讲解
例 3个图的匹配数 依次为3, 3, 4.
4
匹配 (续)
设M为G中一个匹配 vi与vj被M匹配: (vi,vj)M v为M饱和点: M中有边与v关联 v为M非饱和点: M中没有边与v关联 M为完美匹配: G的每个顶点都是M饱和点
例 关于M1, a,b,e,d是饱和点 f,c是非饱和点
M1不是完美匹配
(1)
(2)
(3)
6
Hall定理
定理(Hall定理) 设二分图G=<V1,V2,E>中,|V1||V2|. G中存 在从V1到V2的完备匹配当且仅当V1中任意k 个顶点至少与V2 中的k个顶点相邻(k=1,2,…,|V1|). 由Hall定理不难证明, 上一页图(2)没有完备匹配.
定理 设二部图G=<V1,V2,E>中, 如果存在t1, 使得V1中每个 顶点至少关联 t 条边, 而V2中每个顶点至多关联t条边,则G 中存在V1到V2的完备匹配.
注意: n 阶零图为二分图.
2
二分图的判别法
定理 非平凡无向图G=<V,E>是二分图当且仅当G中 无奇数长度的回路
例 下述各图都是二分图
3
匹配
设G=<V,E>, 匹配(边独立集): 任2条边均不相邻的边子集 极大匹配: 添加任一条边后都不再是匹配的匹配 最大匹配: 边数最多的匹配
匹配数: 最大匹配中的边数, 记为1
M2是完美匹配
M1
M2
5
二分图中的匹配
定义 设G=<V1,V2,E>为二部图, |V1||V2|, M是G中最 大匹配, 若V1中顶点全是M饱和点, 则称M为G中V1 到V2的完全匹配. 当|V1|=|V2|时, 完备匹配变成完美 匹配.
二分图最大匹配及常用建图方法
算法———艺术二分图匹配剖析很多人说,算法是一种艺术。
但是对于初学者的我,对算法认识不是很深刻,但偶尔也能感受到他强大的魅力与活力。
这让我追求算法的脚步不能停止。
下面我通过分析匈牙利算法以及常用建图方式,与大家一起欣赏算法的美。
匈牙利算法匈牙利算法是用来解决最大二分图匹配问题的,所谓二分图即“一组点集可以分为两部分,且每部分内各点互不相连,两部分的点之间可以有边”。
所谓最大二分图匹配即”对于二分图的所有边,寻找一个子集,这个子集满足两个条件,1:任意两条边都不依赖于同一个点。
2:让这个子集里的边在满足条件一的情况下尽量多。
首先可以想到的是,我们可以通过搜索,找出所有的这样的满足上面条件的边集,然后从所有的边集中选出边数最多的那个集合,但是我们可以感觉到这个算法的时间复杂度是边数的指数级函数,因此我们有必要寻找更加高效的方法。
目前比较有效的方法有匈牙利算法和通过添加汇点和源点的网络流算法,对于点的个数都在200 到300 之间的数据,我们是采取匈牙利算法的,因为匈牙利算法实现起来要比网络流简单些。
下面具体说说匈牙利算法:介绍匈牙利之前,先说说“增广轨”。
定义:若P是图G中一条连通两个未匹配顶点的路径,并且属最大匹配边集M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广轨定义总是抽象的下面通过图来理解它。
图中的线段(2->3, 3->1, 1->4)便是上面所说的p路径,我们假定边(1,3)是以匹配的边,(2,3)(1,4)是未匹配的边,则边(4,1)边(1,3)和边(3,2)在路径p上交替的出现啦,那么p就是相对于M的一条增广轨,这样我们就可以用边1,4 和边2,3来替换边1,3 那么以匹配的边集数量就可以加1,。
匈牙利算法就是同过不断的寻找增广轨实现的。
很明显如果二分图的两部分点分别为n 和m,那么最大匹配的数目应该小于等于MIN(n,m); 因此我们可以枚举任第一部分(的二部分也可以)里的每一个点,我们从每个点出发寻找增广轨,最后吧第一部分的点找完以后,就找到了最大匹配的数目,当然我们也可以通过记录找出这些边。
离散数学中的图的匹配和二分图
在离散数学中,图论是一门重要的理论基础课程,它研究的是由节点和边构成的图结构。
图的匹配和二分图是图论中的两个重要概念,它们在现实生活中有着广泛的应用。
首先,我们来介绍一下图的匹配。
图的匹配指的是在一个图中选取一些边,使得这些边彼此不相交,即任意两条边不共享同一个顶点。
图的匹配问题可以用最优化问题来描述,既需要满足匹配条件,还需要满足某种优化目标。
例如,在一个社交网络图中,选择一些用户与其他用户进行配对,使得两个不认识的用户不会被配对在一起,同时目标是使得配对用户的兴趣爱好相似度最大化。
在这个问题中,边表示用户之间是否认识,而边的权值表示兴趣爱好的相似度。
其次,我们来介绍一下二分图。
二分图是一种特殊的图结构,它可以被划分为两个独立的顶点集合,使得同一个顶点集合内的顶点之间没有边相连。
换句话说,二分图中不存在奇圈。
二分图的一个典型例子是婚姻匹配问题。
假设有n个男性和n个女性,他们之间有多种可能的配对方式,但是每个人只能与另一个不同性别的人结婚。
这时,我们可以用一个二分图来表示这个问题,其中男性和女性分别作为两个顶点集合,边表示可能的配对。
然后,我们可以使用图的匹配算法来找到一个最佳匹配方案。
图的匹配和二分图在离散数学中有着重要的研究价值和应用价值。
首先,图的匹配可以用于解决资源分配问题。
例如,在一个工厂中,有m个任务需要分配给n个员工进行处理,每个员工对某些任务有一定的能力要求,而每个任务也需要一定的时间完成。
这时,我们可以将员工和任务分别作为两个顶点集合,边的权值表示员工对任务的能力是否满足要求和任务完成时间。
然后,我们可以使用图的匹配算法来找到一个最佳的任务分配方案,使得员工的工作量最小。
其次,二分图可以用于解决社交网络分析问题。
如今,社交网络已经成为人们日常生活中重要的一部分,人们之间通过社交网络平台进行交流和连接。
我们可以使用二分图来表示社交网络的结构,其中一个顶点集合表示用户,另一个顶点集合表示用户之间的好友关系,边的权值表示用户之间的相似性度量。
二分图的最优匹配(KM算法)
我们看出:al>0;修改后的顶标仍是可行顶标;Gl 中仍含 Gl 中的匹配 M;Gl 中至少会出现不属于 M 的 一条边,所以会造成 M 的逐渐增广。
得到可行顶标后求最大匹配:
值都减去 d(因为:d 的定义为 min{ (x,y)| Lx(x)+ Ly(y)- W(x,y), x∈ S, y T }(关键,关键),此时属于 S 的 X 均已经减去 d 了,所以不属于 T 的 y 也要减去 d,防止下次循环更改出错)。
Kuhn-Munkras 算法流程: (1)初始化可行顶标的值
现在的问题就是求 d 值了。为了使 A[ i ]+B[j]>=w[i,j]始终成立,且至少有一条边进入相等子图, d 应该等于:
Min{A[i]+B[j]-w[i,j] | Xi 在交错树中,Yi 不在交错树中}。
改进
以上就是 KM 算法的基本思路。但是朴素的实现方法,时间复杂度为 O(n4)——需要找 O(n)次增广 路,每次增广最多需要修改 O(n)次顶标,每次修改 顶标时由于要枚举边来求 d 值,复杂度为 O(n2)。 实际上 KM 算法的复杂度是可以做到 O(n3)的。我们给每个 Y 顶点一个“松弛量”函数 slack,每次 开 始找增广路时初始化为无穷大。在寻找增广路的过程中,检查边(i,j)时,如果它不在相等子图中,则 让 slack[j]变成原值与 A[ i ]+B[j]-w[i,j]的较小值。这样,在修改顶标时,取所有不在交错树中的 Y 顶点的 slack 值中的最小值作为 d 值即可。但还要注意一点:修改顶标后,要把所有的不在交错树中的 Y 顶点的 slack
指派问题的数学模型
指派问题的数学模型
数学中有多种指派问题模型,以下是几个常见的:
1. 二分图匹配模型:将指派问题看作是二分图中的最大匹配问题。
将待分配的任务和接受任务的对象分别看作是二分图中的两个部分,将每个待分配任务和每个对象之间连一条边,并赋予权值表示在该情况下指派此任务给此对象的效果。
最终目标是找到一种方案,使得总权值最大。
2. 匈牙利算法:是解决二分图匹配问题的经典算法,能够在多项式时间内求解最大匹配问题。
3. 线性规划模型:将指派问题转化为线性规划模型,通过最小化或最大化某个目标函数的方式,得到满足约束条件的最优解。
4. 费用流模型:将指派问题看作是最小费用最大流问题,将待分配的任务看作源点,接受任务的对象看作汇点,建立相应的网络流模型,并加入相应的约束条件,通过找到最小费用最大流的方式得到最优解。
二分图与匹配_黄哲威
CF1268B. Domino for Young
对格子子进行行行黑黑白白染色色,答案是两种格子子数量量的较小小值
考虑建二二分图,容易易证明匹配一一定可以配满,因为任意一一个白白格到 任意一一个黑黑格之间都能找一一个增广广路路
CF623A.Graph and String
n 个结点的无无向图,每个结点标号”abc” 三个字⺟母其中一一个。
随便便选一一个点,染成白白色色,然后把它相邻的点染成黑黑色色,再把 这些点相邻的点染成黑黑色色,以此类推。
用用 dfs 或者 bfs 实现这个过程。
如果染色色过程中有矛矛盾,说明这个图不不是二二分图。
匈牙牙利利算法
把二二分图分为 A, B 两个集合,依次枚举 A 中的每个点, 试图在B集合中找到一一个匹配。
这就是匈牙牙利利算法的过牙利利算法
顶点覆盖和独立立集
定义:假如选了了一一个点就相当于覆盖了了以它为端点的所有边。最小小顶 点覆盖就是选择最少的点来覆盖所有的边。
定理理:最小小顶点覆盖等于二二分图的最大大匹配。
设最大大匹配是M,考虑最小小顶点覆盖:
(1)M个点是足足够的。就是说他们覆盖最大大匹配的那M条边后,假设 有某边 e 没被覆盖,那么把 e 加入入后会得到一一个更更大大的匹配,出现矛矛 盾。
练习题
CF-gym-101755D. Transfer Window
n 个球员,有 m 个关系,表示某个球员可以换成另外一一个球员。现 在有某 K 个球员,想要 K 个其它球员(可能已经有了了可能没有), 问是否有交换方方案。
n <= 300, m <= 90000
CF-gym-101755D. Transfer Window
改变限制,要求 2i 和 2i − 1 ⻝食食物类型不不同
二分图的完备匹配
X4
X5
Y1
Y2
Y3
Y4
Y5
X1
X2
X3
X4
X5
Y1
Y2
Y3
Y4
Y5
求二分图最佳匹配的算法——匈牙利算法 变量说明; S——外点集合,初始时为交错树的根; T——内点集合,初始时为空; N(S)——与S中的顶点相邻的顶点集合。显然,若N(S)= T,表明与任一外点相连的端点都在内点集合里,找不出一 条不属于交错树的边,图G无完备匹配; M——匹配边集合; E(P)——可增广轨P上的边。 · M配边与非匹配边对换,P轨外的匹配边不变,使得M改进 成一个多包含一条边的匹配。
mep进行对称差运算的结果为可增广轨p上的匹配边与非匹配边对换p轨外的匹配边不变使得m改进成一个多包含一条边的匹配
二分图的完备匹配
某公司有工作人员X1,X2,…,Xm,他们去做 工作Y1,Y2,…,Yn,每人适合做其中的一项或几 项工作,问能否每人都分配一项合适的工作。 这个问题的数学模型是:构造一个二分图G, 顶点划分为两个部分: 一个是工作人员集合X={Xl,X2,…,Xm}, 一个是工作集合Y={Y1,Y2,…,Yn}, 当且仅当Xi适合干工作Yi时,Xi与Yi之间连一条边。 问是否能从G中得出一个不含未盖点的匹配,这种 将G的每一个顶点盖住的匹配称为二分图的完备匹 配。
可能存在完备匹配的图是否仅限于二分图呢?答案 是否定的。数学家在做了大量的图论分析后得出: (1)G是K(K>0)次正则二分图; (2)G是无桥的三次正则图; (3)G在去除任意一个顶点子集S后,其子图中含 顶点数为奇数的连通分支个数不大于|S|。 具有上述3个特征的图肯定有完备匹配。 特别是特征(3),是完备匹配的充分必要条件:含特 征(3)的图一定有完备匹配;有完备匹配的图也一定 含有特征(3)。
二分图的匹配
第九章二分图中的匹配三个典型问题:(1)在一个有禁止位置的m×n棋盘上,能放置非攻击型车的最多个数是多少?(2)在一个有禁止位置的m×n棋盘上,能放置多米诺牌覆盖的最多个数是多少?(3)一个公司有n个工作空缺,需要有一定技能的人填补,同时有m个人申请这些项工作,每人能胜任n项工作中的若干项,问最多有多少项工作能找到合适的人选?9.1 一般的问题描述定义1:令X={x1, x2, …,x m}, Y={y1,y2, …,y n},且X∩Y=Ф,而△是序偶e=(x,y)的集合,其中x ∈X,y∈Y,那么三元组G=(X,△,Y)称作二分图。
定义2:令G=(X,△,Y)是一个二分图,边集△的子集M,若M中没有两条边存在公共点,称M是二分图G的一个匹配。
定义3:设G是一个二分图,定义ρ(G)={∣M∣:M是G的一个匹配}为二分图G的最大匹配边数。
9.2 匹配定义1:G=(X,△,Y),X={x1, x2, …,x m}, Y={y1,y2, …,y n},满足∣M*∣=ρ(G)的匹配M*称为二分图G的最大匹配。
一般M*不唯一,且∣M*∣=ρ(G)≤min{m,n}。
寻找M*的困难点:(1)若已知ρ(G),那么遍历所有可能的匹配会找到M*,但搜索量巨大;(2)一般ρ(G)并不事先知道,要找到M*,并求出ρ(G)=∣M*∣难度更大。
定义2:令u和v是二分图G=(X,△,Y)的任意两个顶点,连接u和v的互异顶点序列:γ:u=u0, u1, u2, …, u p-1, u p=v使得任意两个相邻顶点有一条边连接,即:{ u0, u1},{ u1, u2},…, { u p-1, u p}∈△,那么称序列γ为二分图G的一个链。
链长等于序列的边数p,若u=v, 链γ也叫圈。
定义3:令M为二分图G=(X,△,Y)中的一个匹配,令M是M的补集,即G的不属于M的边集合,M∪M=△。
令u和v是顶点,且u和v一个是左顶点(即属于X),一个是右顶点(即属于Y),若连接u和v的链满足下列性质:(1)γ的第一、三、五、、、边属于M;(2)γ的第二、四、六、、、边属于M;(3)u和v都不与M的边相连。
二分图最大匹配:匈牙利算法的python实现
⼆分图最⼤匹配:匈⽛利算法的python实现⼆分图匹配是很常见的算法问题,⼀般⽤匈⽛利算法解决⼆分图最⼤匹配问题,但是⽬前⽹上绝⼤多数都是C/C++实现版本,没有python版本,于是就⽤python实现了⼀下深度优先的匈⽛利算法,本⽂使⽤的是递归的⽅式以便于理解,然⽽迭代的⽅式会更好,各位可以⾃⾏实现。
1、⼆分图、最⼤匹配什么是⼆分图:⼆分图⼜称作⼆部图,是图论中的⼀种特殊模型。
设G=(V,E)是⼀个⽆向图,如果顶点V可分割为两个互不相交的⼦集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为⼀个⼆分图。
什么是匹配:把上图想象成3位⼯⼈和4种⼯作,连线代表⼯⼈愿意从事某项⼯作,但最终1个⼯⼈只能做⼀种⼯作,最终的配对结果连线就是⼀个匹配。
匹配可以是空。
什么是最⼤匹配:在愿意从事的基础上,能够最多配成⼏对。
现在要⽤匈⽛利算法找出最多能发展⼏对。
[color=green][size=medium]匈⽛利算法是解决寻找⼆分图最⼤匹配的。
更多⼆分图最⼤匹配的图解可以参考 /5576502/1297344以下是代码,为了图省事使⽤了类,实际上并不需要这样M=[]class DFS_hungary():def__init__(self, nx, ny, edge, cx, cy, visited):self.nx, self.ny=nx, nyself.edge = edgeself.cx, self.cy=cx,cyself.visited=visiteddef max_match(self):res=0for i in self.nx:if self.cx[i]==-1:for key in self.ny: # 将visited置0表⽰未访问过self.visited[key]=0res+=self.path(i)return resdef path(self, u):for v in self.ny:if self.edge[u][v] and (not self.visited[v]):self.visited[v]=1if self.cy[v]==-1:self.cx[u] = vself.cy[v] = uM.append((u,v))return 1else:M.remove((self.cy[v], v))if self.path(self.cy[v]):self.cx[u] = vself.cy[v] = uM.append((u, v))return 1return 0ok,接着测试⼀下:if__name__ == '__main__':nx, ny = ['A', 'B', 'C', 'D'], ['E', 'F', 'G', 'H']edge = {'A':{'E': 1, 'F': 0, 'G': 1, 'H':0}, 'B':{'E': 0, 'F': 1, 'G': 0, 'H':1}, 'C':{'E': 1, 'F': 0, 'G': 0, 'H':1}, 'D':{'E': 0, 'F': 0, 'G': 1, 'H':0}} # 1 表⽰可以匹配, 0 表⽰不能匹配cx, cy = {'A':-1,'B':-1,'C':-1,'D':-1}, {'E':-1,'F':-1,'G':-1,'H':-1}visited = {'E': 0, 'F': 0, 'G': 0,'H':0}print DFS_hungary(nx, ny, edge, cx, cy, visited).max_match()结果为4,是正确的。
二分图及匹配算法
Chapter 3
二分图最佳匹配
-二分图最佳匹配-
定义:图G中权值和最大的完全匹配。
Kuhn-Munkras算法:该算法是通过给每个顶点一个标号(叫做顶标) 来把求最大权匹配的问题转化为求完备匹配的问题的。设顶点Xi的顶标 为A[ i ],顶点Yj的顶标为B[ j ],顶点Xi与Yj之间的边权为w[i,j]。在算法 执行过程中的任一时刻,对于任一条边(i,j),A[ i ]+B[j]>=w[i,j]始终成立。 KM算法的正确性基于以下定理: 若由二分图中所有满足A[ i ]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等 子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。 KM算法流程: (1)初始化可行顶标的值; (2)用匈牙利算法寻找完备匹配; 这样做是O(n^4)的
-稳定婚姻问题-
Байду номын сангаас
求婚拒绝算法(Gale-Shapley算法/延迟认可算法): 先对所有男生进行单身标记,称其为单身狗男。当存在单身狗男时,进行 以下操作:
①选择一位单身狗男在所有尚未拒绝她的女生中选择一位被他排名最优先 的女神;
②女神将正在追求她的单身狗男与其现任进行比较,选择其中排名优先的 男生作为其男友,即若单身狗男优于现任,则现任被抛弃为前任;否则保 留其男友,拒绝单身狗男。 ③若某男生被其女友抛弃,则重新变成单身狗男,至①重复。
Chapter 5
稳定婚姻问题
-稳定婚姻问题-
你们班上有n位男生和n位女生,每个人对异性都有一个排序,表示对他们 的爱恋程度。现在你的任务是使他们凑成CP,使他们的爱情坚不可摧! 满足一下条件的爱情不是坚不可摧的: 男生u和女生v不是CP,但他们爱恋对方的程度都大于爱恋现任 的程度。 因为这样男生u和女生v会抛下已经是CP的那个她/他,另外组成一对。于 是乎多出了两位前任,这样就会让人再也无法相信爱情了! 怎么能避免悲剧的发生呢?