二分图多重匹配
图论中的二分图匹配问题及其算法设计思路

图论中的二分图匹配问题及其算法设计思路图论是数学中一个重要的分支,研究图的性质和结构,以及解决与图相关的问题。
其中,二分图匹配问题是图论中的经典问题之一。
本文将介绍二分图匹配问题的定义、特性,并讨论相关的算法设计思路。
一、二分图匹配问题的定义二分图是一种特殊的图结构,其中的顶点可以分为两个互不相交的集合,且每条边都只连接两个集合之间的顶点。
对于一个二分图,如果存在一种边的划分方式,使得每个顶点都与边集中的一条边相连,那么我们称这个边集为二分图的一个匹配。
二分图匹配问题的目标是寻找出一个匹配,使得匹配的边数最大。
这个问题在实际应用中有许多场景,比如婚姻匹配、求职配对等。
为了解决这个问题,人们提出了多种算法,下面将介绍其中两个常用的算法。
二、匈牙利算法匈牙利算法是用于求解二分图最大匹配的一种经典算法,它基于深度优先搜索的思想。
算法的基本思路是从一个没有匹配边的顶点开始,逐个尝试与其相连的顶点进行匹配,如果能成功匹配则将边加入匹配集合中,如果不能成功匹配则继续尝试下一个顶点。
当所有的顶点都尝试过后,即得到一个最大匹配。
以下是匈牙利算法的伪代码:1. 初始化匹配集合为空2. 从一个未匹配的顶点开始,对其进行深度优先搜索3. 如果找到了增广路径,则更新匹配集合4. 重复步骤2和3,直到无法找到增广路径5. 返回最大匹配匈牙利算法的时间复杂度为O(V*E),其中V表示顶点数,E表示边数。
虽然算法的时间复杂度较高,但它在实际应用中仍然具有一定的效率和适用性。
三、Hopcroft-Karp算法Hopcroft-Karp算法是用于求解二分图最大匹配的另一种算法,它是对匈牙利算法的改进和优化。
Hopcroft-Karp算法的核心思想是通过多次的广度优先搜索来寻找增广路径,从而提高算法的效率。
以下是Hopcroft-Karp算法的伪代码:1. 初始化匹配集合为空2. 初始化标记集合为空3. 利用广度优先搜索寻找增广路径4. 如果找到增广路径,则更新匹配集合5. 重复步骤3和4,直到无法找到增广路径6. 返回最大匹配Hopcroft-Karp算法的时间复杂度为O(E*sqrt(V)),相比于匈牙利算法有较大的优势。
图匹配总结二分图匹配

序言:回忆起最初学习图匹配算法的艰辛与困惑,苦中有乐,但很多时间都浪费在了资料的寻找与甄别上。
因此,在对自己做一次知识总结的同时,整理与记录下了这些文字,希望能够给大家带来一定的帮助。
目录:第一部分:二分图的最大匹配第二部分:五种方式,两类构图第三部分:二分图匹配算法总结第四部分:二分图的最优权值匹配第五部分:一般图的最大匹配第六部分:图匹配题目列表符号说明: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 }据说这是典型的最⼤流题⽬,然⽽为了强⾏安利⼀波⼆分图的多重匹配,就不说成那个了。
第九讲 二分图匹配问题(1)

第九讲二分图匹配问题一、问题设G=(V,{R})是一个无向图。
如顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属两个不同的子集。
则称图G为二分图。
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。
最大匹配在实际中有广泛的用处,求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。
即回溯法,但是这个算法的复杂度为边数的指数级函数。
因此,需要寻求一种更加高效的算法。
二、算法分析二分图的最大匹配有2种实现,网络流和匈牙利算法。
1.匈牙利算法是求解最大匹配的有效算法,该算法用到了增广路的定义(也称增广轨或交错轨):若边集合P 是图G中一条连通两个未匹配顶点的路径,并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
2.由增广路径的定义可以推出下述三个结论:(1). P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
(2). P经过“取反操作”(即非M中的边变为M中的边,原来M中的边去掉)可以得到一个更大的匹配M’。
(3). M为G的最大匹配当且仅当不存在相对于M的增广路径。
3.从而可以得到求解最大匹配的匈牙利算法:(1)置M为空;(2)找出一条增广路径P,通过“取反操作”获得更大的匹配M’代替M;(3)重复(2)操作直到找不出增广路径为止;根据该算法,可以选择深搜或者广搜实现,下面给出易于实现的深度优先搜索(DFS)实现。
三、实现1. 匈牙利算法的算法轮廓bool寻找从k出发的对应项出的可增广路{while(j与k邻接){if(j不在增广路上){把j加入增广路;if(j是未盖点或者从j的对应项出发有可增广路)则从k的对应项出有可增广路,返回true;修改j的对应项为k;}}从k的对应项出没有可增广路,返回false;}2. 匈牙利算法流程3.代码int n, m, match[100]; //二分图的两个集合分别含有n和m个元素,match[i]存储集合m中的节点i在集合n 中的匹配节点,初值为-1。
二分图匹配问题最大匹配以及相关结论多重匹配最大带权匹配带花树算法

⼆分图匹配问题最⼤匹配以及相关结论多重匹配最⼤带权匹配带花树算法⼆分图匹配问题:做法:①匈⽛利算法,时间复杂度O(N*V)②Hopcroft-Karp,时间复杂度O(√N*V)相关结论:①最⼩顶点覆盖(könig定理) ⼆分图的最⼩顶点覆盖=最⼤匹配数②最⼩路径覆盖(不要求⼆分图):在图中找⼀些路径,使之覆盖了图中的所有顶点,且任何⼀个顶点有且只有⼀条路径与之关 最⼩路径覆盖 = 顶点数 - 最⼤匹配配对于有向⽆环图,⾸先拆点,建成⼆分图再进⾏求解·最⼩不相交路径覆盖 建图⽅式:把⼀个的点V拆点成Vx和Vy,如果A连向B,那么就建⼀条Ax连向By的边。
图中有多少条路径,可以以⼀种⽅法得到,就是计算出度为0的点的个数。
如果知道这个就很容易得出这个结论了 ·最⼩相交路径覆盖 做法⾸先跑floyd,求出原图的传递闭包,然后⽤上述⽅法做即可③最⼩边覆盖最⼩边覆盖=图顶点-最⼤匹配⾸先⼀开始,假如⼀条边都不选的话,要覆盖所有的点就必须每个点都选⼀次,也就是n次,然后每选⼀条边就会减少1个,所以结论显⽽易见④最⼤独⽴集最⼤独⽴集=图顶点-最⼤匹配=最⼩边覆盖⼆分图的独⽴数等于顶点数减去最⼤匹配数,很显然的把最⼤匹配两端的点都从顶点集中去掉这个时候剩余的点是独⽴集,这是|V|-2*|M|,同时必然可以从每条匹配边的两端取⼀个点加⼊独⽴集并且保持其独⽴集性质。
⼆分图多重匹配( ⼀ ) 如果x部节点只对应⼀个y部节点,⽽y部节点可以对应多个x部节点,那么这种匹配可以⽤匈⽛利算法来解决解决的问题:⼀个y最多匹配cnt个x是否成⽴,要问⼀个y匹配⼈数最⼤的最⼩值可以⽤⼆分答案来做解决思路:根据匈⽛利算法的思想,这时的link[u]要变成link[u][i],表⽰与y[u]匹配好了的第i个点,⽤vlink[u]记录已经于u点匹配了的点的个数,对于x中的x[k],找到⼀个与他相连的y[i]后,同样判断匈⽛利算法中的两个条件是否成⽴,若满⾜第⼀个条件,直接将x[k],y[i]匹配,否则,如果与y[i]所匹配的点已经达到了饱和,那么在所有与y[i]配合的点中选⼀个点,检查能否找到增⼴路,如果能,就让出位置让x[k]与y[i]匹配( ⼆ )如果x部节点可以匹配多个y部节点,y部节点可以同时匹配多个x部节点,那么应该⽤⽹络流来解决。
二分图匹最大配与最佳匹配

二分图:二分图是这样的一个图,它的顶点可以分为两个集合X和Y。
所有的边关联的两个顶点中,恰好一个属于集合X,一个属于集合Y。
二分图的匹配:给定一个二分图G,M为G边集的一个子集,如果M满足当中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
二分图的最大匹配:二分图的所有匹配中包含边数最多的匹配称为图的最大匹配。
完美(完备)匹配:如果所有点都在匹配边上,称这个最大匹配是完美匹配。
最佳匹配:如果边上带权的话,找出权和最大的匹配叫做求最佳匹配。
增广路径:也称增广轨或交错轨。
若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,。
下面给出关于二分图最大匹配的三个定理1:最大匹配数+ 最大独立集= n + m2:二分图的最小覆盖数= 最大匹配数3:最小路径覆盖= 最大独立集最大独立集是指求一个二分图中最大的一个点集,该点集内的点互不相连。
最小顶点覆盖是指在二分图中,用最少的点,让所有的边至少和一个点有关联。
最小路径覆盖是指一个不含圈的有向图G 中,G的一个路径覆盖是一个其结点不相交的路径集合P,图中的每一个结点仅包含于P 中的某一条路径。
路径可以从任意结点开始和结束,且长度也为任意值,包括0.1求解二分图最大匹配的方法:●匈牙利算法(时间复杂度O(nm))其思想是是通过不断的寻找增广轨实现最大匹配。
●转化为单位容量简单网络的最大流问题(本文不介绍)在二分图的基础上,加入源点s和汇点t,让s与每个X结点连一条边,每个Y结点和t连一条边,所有弧的容量为1。
算法学习:图论之二分图的最优匹配(KM算法)

二分图的最优匹配(KM算法)KM算法用来解决最大权匹配问题:在一个二分图内,左顶点为X,右顶点为Y,现对于每组左右连接XiYj有权wij,求一种匹配使得所有wij的和最大。
基本原理该算法是通过给每个顶点一个标号(叫做顶标)来把求最大权匹配的问题转化为求完备匹配的问题的。
设顶点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)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。
首先解释下什么是完备匹配,所谓的完备匹配就是在二部图中,X点集中的所有点都有对应的匹配或者是Y点集中所有的点都有对应的匹配,则称该匹配为完备匹配。
这个定理是显然的。
因为对于二分图的任意一个匹配,如果它包含于相等子图,那么它的边权和等于所有顶点的顶标和;如果它有的边不包含于相等子图,那么它的边权和小于所有顶点的顶标和。
所以相等子图的完备匹配一定是二分图的最大权匹配。
初始时为了使A[ i ]+B[j]>=w[i,j]恒成立,令A[ i ]为所有与顶点Xi关联的边的最大权,B[j]=0。
如果当前的相等子图没有完备匹配,就按下面的方法修改顶标以使扩大相等子图,直到相等子图具有完备匹配为止。
我们求当前相等子图的完备匹配失败了,是因为对于某个X顶点,我们找不到一条从它出发的交错路。
这时我们获得了一棵交错树,它的叶子结点全部是X顶点。
现在我们把交错树中X顶点的顶标全都减小某个值d,Y顶点的顶标全都增加同一个值d,那么我们会发现:1)两端都在交错树中的边(i,j),A[ i ]+B[j]的值没有变化。
也就是说,它原来属于相等子图,现在仍属于相等子图。
2)两端都不在交错树中的边(i,j),A[ i ]和B[j]都没有变化。
图论中的二分图匹配问题及其算法设计思路

图论中的二分图匹配问题及其算法设计思路二分图匹配问题是图论中的重要问题之一。
二分图是指一个图的顶点可以分为两个互斥的集合,并且图的边只能连接两个集合之间的顶点。
二分图匹配的目标是找到一个匹配,即找到一种对应关系,使得图中的所有顶点都能够与另一个集合中的顶点相连。
在实际应用中,二分图匹配有着广泛的应用。
比如在招聘网站中,求职者和企业可以被看作是一个二分图,通过匹配求职者和企业,可以使得求职者找到合适的工作岗位,企业找到合适的人才。
在网络流量调度中,可以将网络中的节点和链路看作一个二分图,通过匹配可以实现有效的数据传输。
那么如何解决二分图匹配问题呢?目前比较常用的算法有匈牙利算法和增广路径算法。
匈牙利算法,也称为增广路径算法,是解决二分图最大匹配问题的一种经典算法。
该算法从某一个未匹配的顶点开始,尝试去匹配其他的顶点。
如果当前顶点没有匹配的边,那么匈牙利算法会尝试寻找一个增广路径,即一条能够增加匹配数的路径。
当不存在增广路径时,匈牙利算法会返回当前匹配的结果。
增广路径算法是一个递归的过程。
首先,我们从一个未匹配的顶点开始,将其标记为已访问。
然后遍历与该顶点相连的所有边,如果边的另一个顶点没有被访问过,那么我们尝试去匹配这个顶点。
如果匹配成功,那么整个算法就结束了,返回当前的匹配结果。
如果匹配失败,我们需要尝试寻找另一个增广路径,这时我们会递归地调用增广路径算法,从当前的匹配边的另一个顶点开始。
增广路径算法的时间复杂度为O(V*E),其中V是顶点数,E是边数。
在实际应用中,匈牙利算法已经被广泛应用,因为其算法简单易懂,同时具有较好的计算效率。
除了匈牙利算法,还有其他一些解决二分图匹配问题的算法,比如多项式时间的Hopcroft-Karp算法和Edmonds的算法。
这些算法在不同的应用场景中,可能有着更好的性能表现。
总结来说,二分图匹配问题在图论中具有重要的地位,它可以通过匈牙利算法等多种算法来解决。
在实际应用中,二分图匹配问题可以用于求职招聘、网络流量调度等领域。
离散数学_二分图与匹配

二分图与匹配
满足如下条件的无向图G=<V,E>有非空集合X,Y:X∪Y=V,X∩Y=∅,且每个vᵢ ,vⱼ∈E,都有:vᵢ∈X∧vⱼ∈Y,或者vᵢ∈Y∧vⱼ∈X可以用G=<X,E,Y>表示二分图
完全二分图 : 如果X,Y中任意两个顶点之间都有边,则称为完全二分图
匹配 : 将E的子集M称作一个匹配
最大匹配 : 如果M中的任意两条边都没有公共端点边数最多的匹配称作最大匹配
完全匹配 : 如果X(Y)中的所有的顶点都出现在匹配M中,则称M是X(Y)-完全匹配 如果M既是X-完全匹配,又是Y-完全匹配,称M是完全匹配最大匹配匈牙利算法 : ①任意取一个匹配M (可以是空集或只有一条边) ②令S是非饱和点(尚未匹配的点)的集合 ③如果S=∅,则M已经是最大匹配 ④从S中取出一个非饱和点u₀作为起点,从此起点走交错路(交替属于M和非M的边构成的极大无重复点通路或回路)P ⑤如果P是一个增广路(P的终点也是非饱和点),则令M=M⊕P=(M-P)∪(P-M) ⑥如果P都不是增广路,则从S中去掉u₀,转到step3。
二分图匹配

KM算法是通过给每个顶点一个标号(叫做顶标)来把求最大权 匹配的问题转化为求完备匹配的问题。设顶点Xi的顶标为lx[i], 顶点Yi的顶标为ly[i],顶点Xi与Yj之间的边权为w[i,j]。在算法执 行过程中的任一时刻,对于任一条边(i,j),lx[i]+ly[j]>=w[i,j]始终 成立。 KM算法的正确性基于以下定理: 若由二分图中所有满足lx[i]+ly[j]=w[i,j]的边(i,j)构成的子图 lx[i]+ly[j]=w[i,j] (i,j) (称做相等子图)有完备匹配,那么这个完备匹配就是二分图 的最大权匹配。 上面的定理我们就先别理它,直接看个例子来理解KM算法.回 过头就会懂了,现在我们先把一句话记住 对于由二分图中所有满足lx[i]+ly[j]=w[i,j]的边(i,j)构成的子图, 称作相等子图(或导出子图).随便叫,总之先记住就行
1 2 3 4 5 6 1 2 3 4 5 6
我们总结可以看出增广路径有这样的性质: (1)有奇数条边。 (2)起点在二分图的左半边,终点在右半边。 (3)路径上的点一定是一个在左半边,一个在右半边,交替出现。 (其实二分图的性质就决定了这一点,因为二分图同一边的点 之间没有边相连,不要忘记哦。) (4)整条路径上没有重复的点。 (5)起点和终点都是目前还没有配对的点,而其它所有点都是已 经配好对的。
最小点覆盖 PKU 3041:(类似的有PKU3020) 问题: 假如你现在正处在一个N*N的矩阵中,这个矩阵里面有K个 障碍物,你拥有一把武器,一发弹药一次能消灭一行或一列 的障碍物,求最小的弹药消灭全部障碍物
输入为: NK 接下来有K行,每行包含障碍物的坐标,即r行c列; 如:
34 11 13 22 32 输出为: 花费最小的弹药数
二分图及二分图匹配及并查集

二分图及其二分图的匹配如果可以以某一种方式将题目中的对象分成两个互补的集合,而需要求得他们之间满足某种条件的“一一对应”关系时,往往可以抽象出对象以及对象之间的关系,构造二分图,然后利用匹配算法来解决。
这类题目通常需要考察选手构建二分图模型、设计匹配算法、并对其算法进行适当优化等方面的能力。
通过DFS判别二分图二分图分成两个顶点子集X和Y。
若顶点i属于集合X,则相邻点j必属于集合Y。
proc dfs(d,集合标志); /*从d置入某集合的初始状态出发,判别二分图*/定义d的相邻点u的数据类型;{ if 非二分图标志then exit;if d已属于本集合then exit;if d属于另一集合then 失败退出;设d的本集合标志;取d的第1个相邻点u;while u存在do{ dfs(u,另一集合标志);u←d的下一个相邻点};};/* dfs */依次搜索每个无集合标志的顶点i,执行dfs(i,X集合标志)。
最后未失败退出的情况,则说明图为二分图。
*例题:双栈排序【问题描述】Tom最近在研究一个由趣的排序问题。
如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。
操作a:如果输入序列不为空,将第一个元素压入栈S1操作b:如果栈S1不为空,将S1栈顶元素弹出至输出序列操作c:如果输入序列不为空,将第一个元素压入栈S2操作d:如果栈S2不为空,将S2栈顶元素弹出至输出序列如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n,Tom 就称为P是一个“可双栈排序序列”。
例如(1,3,2,4)就是一个“可双栈排序序列”,而(2,3,4,1)不是。
下图描述了一个将(1,3,2,4)排序的操作序列:<a,c,c,b,a,d,d,b>。
当然,这样的操作序列有可能有几个,对于上例(1,3,2,4),<a,c,b,c,a,d,d,b>是另外一个可行的操作序列。
二分图及匹配算法

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的那个她/他,另外组成一对。于 是乎多出了两位前任,这样就会让人再也无法相信爱情了! 怎么能避免悲剧的发生呢?
主要定理二分图的最大匹配算法二分图的带权重的最大匹配

2021/2/13
山东大学 软件学院
22
时间复杂度分析
令|S| = m,|T| = n,假设 m n。 找一条增广路(或判断不能找到)标号算法最多进行 O(mn)
次检查(因为最多有这么多条边)。 初始匹配最多被增广 m 次。 所以,总的计算量为 O(m2n)。
2021/2/13
山东大学 软件学院
2021/2/13
山东大学 软件学院
17
例子
1
6
2
72
3
82
4
9
5
10
找到一条增广路(2, 8)。更新M。
2021/2/13
山东大学 软件学院
18
例子
1
63
2
7
3
83
4
93
5
10 3
找到一条增广路(3, 10)。更新M。
2021/2/13
山东大学 软件学院
19
例子
2021/2/13
1 2 10 3 4 5
2021/2/13
山东大学 软件学院
4
例子
2021/2/13
山东大学 软件学院
5
定理
定理:记G’上的最大流为f*,流值为|f*|。G上的最大匹配 为M*。则|f*| = |M*|。 证明:首先证|f*| |M*|。 给定最大匹配M*,令G’上M*中的边的流值为1,s到M*匹 配的V一侧点的各条边上流值为1,M*匹配的U一侧点到t的 各条边上流值为1,则构造了一个流值为|M*|的流f。 因此,显然有|f*| |M*|。 再证|f*| |M*|。 设f*为G’上的最大流。 由整流定理,G’上每条边上的流值为整数。由于每条边的 容量均为1,因此G’上每条边的流值不是0就是1。
二分图多重匹配算法在煤矿物资平衡利库中的研究

二分图多重匹配算法在煤矿物资平衡利库中的研究KANG Peng;LIU Chang-long【摘要】本文通过建立标准的平衡利库权值数据模型,并引入二分图多重匹配算法,按照“先利库、后采购”的原则,多层级开展煤矿物资平衡利库工作.该平衡利库功能动态通盘考虑利库优先级、已利库数量、剩余数量等信息,自动推荐最优利库方案,提高利库的匹配程度,从而实现的全过程平衡利库.【期刊名称】《价值工程》【年(卷),期】2018(037)036【总页数】3页(P29-31)【关键词】二分图;多重匹配;平衡利库;ERP【作者】KANG Peng;LIU Chang-long【作者单位】;【正文语种】中文【中图分类】F2510 引言近年来,随着社会的不断进步和煤炭需求的飞速发展,确保煤矿稳定高效运行成为各大煤碳公司工作的重中之重。
物资管理作为煤矿建设和生产过程中不可或缺的一个重要环节。
大型煤碳集团公司的生产设备分布地域广泛,导致煤矿企业在不同煤矿形成多个库存地点,各级仓库保管着各类项目物资、检修物资、抢修物资和可再利用的拆旧物资等,其中不乏长期未使用的结余物资,这些物资中常常会因为长期保存而导致使用价值降低或报废,因此大型煤碳企业如何减少库存物资储备,提高库存物资利用率,一直是煤碳企业物资管理部门所追求的目标。
1 平衡利库及存在问题大型煤碳企业按照传统的异地分散的多库存管理模式,由于仓库间的信息交互贫乏,不能最大效率利用存库间的信息资源,导致形成了多个库存物资的信息孤岛。
平衡利库针对现有库存和预计需求情况,结合安全库存量来决定采购数量,其中涉及物资需求管理、库存管理、采购管理等多个环节。
以某大型煤炭集团公司为例,ERP系统已稳定运行多年,系统中含有大量的可利库物资,不仅占用了大量的企业库存资金,而且对于仓储管理也增加了很多工作,不利于企业的正常运营。
考虑到可利库物资与需求计划的匹配情况来看,平衡利库的匹配功能还有待加强,以便能够更大程度减少库存物资数量,为此不仅能够充分利用现有库存物资,增加资金流动性,同时也能降低仓库的运维成本。
二分图多重匹配问题

⼆分图多重匹配问题解决什么问题:⼆分图最⼤匹配要求每个顶点只使⽤⼀次,即⼀连⼀。
那么多重匹配就是解决⼀连多的问题的。
⽐如给你n个联系⼈,你要把他们分在m个 组⾥⾯,给你每⼀个联系⼈可以放在那个组⾥⾯。
再给你⼀个限制条件——每个组⾥⾯最多可以放⼊多少⼈,问你可不可以分组成功解决⽅法:⼆分图多重匹配分为⼆分图多重最⼤匹配与⼆分图多重最优匹配两种,分别可以⽤最⼤流与最⼤费⽤最⼤流解决。
(1)⼆分图多重最⼤匹配:在原图上建⽴源点S和汇点T,S向每个X⽅点连⼀条容量为该X⽅点L值的边,每个Y⽅点向T连⼀条容量为该Y⽅点L值的边,原来⼆分图中各边在新的⽹络中仍存在,容量为1(若该边可以使⽤多次则容量⼤于1),求该⽹络的最⼤流,就是该⼆分图多重最⼤匹配的值。
(2)⼆分图多重最优匹配:在原图上建⽴源点S和汇点T,S向每个X⽅点连⼀条容量为该X⽅点L值、费⽤为0的边,每个Y⽅点向T连⼀条容量为该Y⽅点L值、费⽤为0的边,原来⼆分图中各边在新的⽹络中仍存在,容量为1(若该边可以使⽤多次则容量⼤于1),费⽤为该边的权值。
求该⽹络的最⼤费⽤最⼤流,就是该⼆分图多重最优匹配的值。
⼆分图多重匹配问题可以使⽤最⼤流的⽅法来解决,也可以使⽤⼆分图多重匹配来解决(本篇⽂章⽤⼆分图多重匹配来解决问题)例题:POJ 2289题意:有n个⼈和m个⼩组,要求每⼀个⼈只能属于⼀个⼩组,现在已经给出每个⼈可以归属的⼩组编号(从0到M-1)。
设所有⼩组中⼈数的最多的⼩组所拥有的⼈数为num,现在让你求num 最⼩是多少.代码:1 #include<stdio.h>2 #include<algorithm>3 #include<string.h>4 #include<iostream>5 #include<queue>6 #include<vector>7using namespace std;8const int maxn=1010;9int visit[maxn],maps[maxn][maxn],ans,n,m;10struct shudui11 {12int cnt;13int match[maxn];14 }link[maxn];15bool dfs_solve(int x,int limit)16 {17for(int i=1;i<=m;++i)18 {19if(!visit[i] && maps[x][i])20 {21 visit[i]=1;22if(link[i].cnt<limit)23 {24 link[i].match[++link[i].cnt]=x;25return1;26 }27for(int j=1;j<=link[i].cnt;j++)28 {29if(dfs_solve(link[i].match[j],limit))30 {31 link[i].match[j]=x;32return1;33 }34 }35 }36 }37return0;38 }39bool hungran(int limit)40 {41 memset(link,0,sizeof(link));42for(int i=1;i<=n;++i)43 {44 memset(visit,0,sizeof(visit));45if(!dfs_solve(i,limit))46return0;47 }48return1;49 }50int main()51 {52while(~scanf("%d%d",&n,&m))53 {54if(!n && !m) break;55char s[20],ch;56 memset(maps,0,sizeof(maps));57for(int i=1;i<=n;++i)58 {59int x;60 scanf("%s",s);61while(1)62 {63 scanf("%d%c",&x,&ch);64 maps[i][x+1]=1;65if(ch=='\n')66break;67 }68 }69int l=1,r=n;70int ans=n,mid;71while(l<=r)72 {73 mid=(l+r)>>1;74if(hungran(mid))75 {76 r=mid-1;77 ans=mid;78 }79else l=mid+1;80 }81 printf("%d\n",ans);82 }83return0;84 }View Code可见,⼆分多多重匹配只是在⼆分图最⼤匹配的基础上改变了dfs_solve()函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
二分图多重匹配问题
多重匹配是建立在单重匹配的基础上的,我们先回顾下单重匹配的时候,我们用一个数组cm[i]来表示与i匹配的点,而多重匹配的时候我们用的是一个结构体:
struct p
{
int girl[MAXN],num;
}cm[MAXN];
其中cm[i].num代表当前已经有多少个与i进行匹配了,与之匹配的点保存在cm[i].girl[]中。
还有一个不同的地方是在找增广路的时候,单重匹配是直接判断cm[i]是否等于-1,即是否已经匹配过,如果没匹配过则找增广路结束,否则沿着cm[i]继续找增广路。
多重匹配也是相似的方法,如果与cm[i]匹配的个数少于最大可匹配数的时候,同样找增广路结束,否则沿着所以与cm[i]匹配的点继续找增广路,只要其中有一个点找到了增广路就可以了。
关键代码如下:
if(cm[i].num<dm[i])
{
cm[i].girl[cm[i].num++]=t;
//cn[t]=i;
return 1;
}
else
for(j=0;j<cm[i].num;j++)
if(dfs(cm[i].girl[j]))
{
cm[i].girl[j]=t;
//cn[t]=i;
return 1;
}
当然,也可以拆点然后用一般的二分图匹配来做。
2. 最大流
此题如果用最大流算法做的话,建图非常简单,直接添加源点S和汇点T,对于每一个MM i连一条Sài,容量为1,对于每一个GG j,连一条jàT,容量为cj,如果GG j想要包养MM i,则连一个iàj,容量为INF的边。
然后从S到T求一次最大流,最大流值就是所求的答案(证明略)。