图论二分图最大匹配算法

合集下载

图论算法之KM算法

图论算法之KM算法

bool find(int i) {
S[i]=1;
for (int j=1;j<=n;j++) if (!T[j]) {
if (Lx[i]+Ly[j]==w[i][j]) {
T[j]=1;
if (!match[j] || find(match[j])) {
match[j]=i;
return true;
X
-a
Y
+a
void update(){
int a=INF_INT; for (int i=1;i<=n;i++) if (S[i]){
for (int j=1;j<=n;j++) if (!T[j]) a=min(l(x)+l(y)-w[i][j]);
} for (int i=1;i<=n;i++){
如何判断是否存3488 Tour
求一个方案,使得一个图能够被一个或者多个环 做覆盖,每个点只能属于一个环,使得所有环的 权值和最佳。。。
拆点
• 一个玄学。。。 HDU 2853 Assignment
已给出一个匹配,最达到最大匹配需要改变 几次原有的匹配。
让所有的权值都扩大100倍,然后再让原有的 匹配的权值+1 int ans=KM(); 最大值 ans/100; 改变次数 n-ans%100;
}
}
w[i][j]);
else slack[j]=min(slack[j],Lx[i]+Ly[j]-
}
return false;
}
void update() {
int a=INF_INT;

图论:二分图多重匹配

图论:二分图多重匹配

图论:⼆分图多重匹配使⽤最⼤流和费⽤流解决⼆分图的多重匹配之前编辑的忘存了好⽓啊。

本来打算学完⼆分图的乱七⼋糟的匹配之后再去接触⽹络流的,提前撞到了之前我们说的⼆分图最⼤匹配和⼆分图最⼤权匹配有⼀个特点,那就是没个点只能与⼀条边相匹配如果规定⼀个点要与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 }据说这是典型的最⼤流题⽬,然⽽为了强⾏安利⼀波⼆分图的多重匹配,就不说成那个了。

二分图理论

二分图理论

*7.5 二部图及匹配7.5.1二部图在许多实际问题中常用到二部图,本节先介绍二部图的基本概念和主要结论,然后介绍它的一个重要应用—匹配。

定义7.5.1 若无向图,G V E =的顶点集V 能分成两个子集1V 和2V ,满足(1)12V V V =,12V V φ=;(2)(,)e u v E ∀=∈,均有1u V ∈,2v V ∈。

则称G 为二部图或偶图(Bipartite Graph 或Bigraph),1V 和2V 称为互补顶点子集,常记为12,,G V V E =。

如果1V 中每个顶点都与2V 中所有顶点邻接,则称G 为完全二部图或完全偶图(Complete Bipartite Graph),并记为,r s K ,其中12,r V s V ==。

由定义可知,二部图是无自回路的图。

图7-55中,(),(),(),(),()a b c d e 都是二部图,其中(),(),(),()b c d e 是完全二部图1,32,32,43,3,,,K K K K 。

图7-55二部图示例显然,在完全二部图中,r s K 中,顶点数n r s =+,边数m rs =。

一个无向图如果能画成上面的样式,很容易判定它是二部图。

有些图虽然表面上不是上面的样式,但经过改画就能成为上面的样式,仍可判定它是一个二部图,如图7-56中()a 可改画成图()b ,图()c 可改画成图()d 。

可以看出,它们仍是二部图。

图7-56二部图示例定理7.5.1 无向图,G E =为二部图的充分必要条件为G 中所有回路的长度均为偶数。

证明 先证必要性。

设G 是具有互补节点子集1V 和2V 的二部图。

121(,,,,)k v v v v 是G 中任一长度为k 的回路,不妨设11v V ∈,则211m v V +∈,22m v V ∈,所以k 必为偶数,不然,不存在边1(,)k v v 。

再证充分性。

设G 是连通图,否则对G 的每个连通分支进行证明。

算法学习:图论之二分图的最优匹配(KM算法)

算法学习:图论之二分图的最优匹配(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]都没有变化。

程序设计竞赛常用算法

程序设计竞赛常用算法

程序设计竞赛常用算法1.排序算法:排序是一个基本的算法问题,常见的排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序等。

这些排序算法有各自的优势和适用场景,需要根据具体问题需求选择合适的算法。

2.图论算法:图论是程序设计竞赛中经常出现的重要领域。

常见的图论算法有深度优先(DFS)、广度优先(BFS)、Dijkstra算法、Floyd-Warshall算法、拓扑排序、最小生成树等。

这些算法可以用于解决最短路径、连通性、最大流最小割等问题。

3.动态规划:动态规划是一种常用于解决优化问题的算法。

该算法通过将问题分解成子问题,并记录子问题的解来求解原问题的最优解。

常见的动态规划算法有背包问题、最长公共子序列(LCS)、最大子序列和等。

4.字符串处理算法:字符串处理是程序设计竞赛中常见的问题。

常见的字符串处理算法有KMP算法、哈希算法、字符串匹配等。

这些算法可以用于解决模式匹配、字符串、字符统计等问题。

5.数学算法:数学算法在程序设计竞赛中也经常被使用。

常见的数学算法有质因数分解、素数筛、快速乘法、高精度计算等。

这些算法可以用于解决数论、计算几何、概率等问题。

6.图形算法:图形算法主要用于处理图像和几何图形。

常见的图形算法有扫描线算法、凸包算法、几何运算等。

这些算法可以用于解决图像处理、三维建模等问题。

7.树和图的遍历算法:树和图的遍历算法是程序设计竞赛中常用的算法之一、常见的树和图的遍历算法有先序遍历、中序遍历、后序遍历、深度优先(DFS)、广度优先(BFS)等。

这些算法可以用于解决树和图的构建、路径等问题。

8.最大匹配和最小割算法:最大匹配算法用于求解二分图的最大匹配问题,常见的算法有匈牙利算法。

最小割算法用于求解图的最小割问题,常见的算法有Ford-Fulkerson算法。

这些算法可以用于解决网络流和二分图匹配等问题。

9.贪心算法:贪心算法是一种常用于优化问题的算法。

该算法通过每一步选择局部最优解来达到全局最优解。

数学建模-二分图匹配

数学建模-二分图匹配


解题思路:本题是一道典型的二分图最大匹配 题。采用匈牙利算法。本题的构图是这样的, 左右两边的x和y,分别是x学生,y课程。那么 已知哪些学生可以学哪些课,也就是在x的点 和 y的点之间首先连上线。求xy的最大匹配。如果 有P个学生做了课代表,那么就是P门课程都有 课代表了。
例题1 Courses(hdu1006)
X学生
1 2 3
Y课程
1 2 3
样例 3
(1)建图
3 3 1 2 3 2 1 2 1 1
例题1 Courses(hdu1006)
X学生
1 2 3
Y课程
1 2 3
X学生
1 2 3
Y课程
1 2 3 连接 x1-y1 x2-y2 得到此 匹配, 匹配数 为2.
(1)建图
(2)
例题1 Courses(hdu1006)
(5)
(4)
例题1 Courses(hdu1006)
X学生
1
2 3
Y课程
1
2 3 1 2 3 1 2 3
1
2 3
1
2 3
(1)
1 2 1 2 1 2
(2)
1 2
(3)
3
3
3
3
(4)
(5)
#include<iostream> int link[303][303]; int used[303],mathy[303]; using namespace std; int P,N; int find(int x) {//x学生可以匹配到某课程 么 //可以返回1,不可以返回0 … } int MMG() { //计算最大匹配数, 调用了find … } int main( ) {int x,y,i,j; int cases; scanf("%d",&cases);

二分图匹配(匈牙利算法)

二分图匹配(匈牙利算法)

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的定点 数-最小路径覆盖中的边数

maxcardinality用法举例

maxcardinality用法举例

maxcardinality用法举例简介在图论中,最大基数匹配(m ax ca rd in al i ty)是一个重要的概念,它用于描述无向图中的最大匹配问题。

本文将结合实例,介绍m a xc ar di na li ty的基本概念、算法和应用。

基本概念最大基数匹配是指在一个无向图中,找到最大的匹配集合,使得集合中的边数最多。

匹配的定义是指图中某些边的集合,其中任意两条边都不相邻。

在应用场景中,图的节点可以表示为两个集合A和B,边表示A中的元素与B中元素之间的关联关系。

最大基数匹配的目标是找到A和B之间的最佳关联,以最大化匹配的边数。

算法介绍在求解最大基数匹配问题时,常用的算法包括二分图最大基数匹配算法和增广路径算法。

1.二分图最大基数匹配算法:-步骤1:初始化一个空的匹配集合。

-步骤2:从A中的每个元素开始,不断寻找增广路径(即可以扩展匹配的路径)。

-步骤3:如果找到增广路径,则更新匹配集合。

-步骤4:重复步骤2和步骤3,直到无法找到增广路径为止。

-步骤5:输出最大基数匹配结果。

2.增广路径算法:-步骤1:初始化一个空的匹配集合。

-步骤2:从A中的每个元素开始,不断寻找增广路径。

-步骤3:在增广路径中,奇数次访问A中的元素,偶数次访问B中的元素。

-步骤4:如果找到增广路径,则更新匹配集合。

-步骤5:重复步骤2和步骤4,直到无法找到增广路径为止。

-步骤6:输出最大基数匹配结果。

实例分析假设有一个电视节目策划团队,需要将每个员工分配到不同的节目中。

员工集合A包括编剧、导演和演员,节目集合B包括电视剧、电影和综艺节目。

他们之间的关联关系如下:-编剧与电视剧、电影存在关联;-导演与电视剧、综艺节目存在关联;-演员与电影、综艺节目存在关联。

我们的目标是找到最佳的分配方案,使得每个员工只参与一个节目,并且最大化分配的数量。

采用ma xc ar din a li ty算法可以解决这个问题。

步骤1:初始化空的匹配集合开始时,我们先将匹配集合置空。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

二分图最大匹配算法
令G = (X,*,Y)是一个二分图,其中,X = {x1,x2,...xm}, Y = {y1,y2,...yn}。

令M为G中的任一个匹配。

1)讲X的所有不与M的边关联的顶点标上(@),并称所有的顶点为未被扫描的。

转到2)。

2)如果在上一步没有新的标记加到X的顶点上,则停止。

否则转到3)。

3)当存在X被标记但未被扫描的顶点时,选择一个被标记但未被扫描的X的顶点,比如,xi,用(xi)标记Y的所有顶点,这些顶点被不属于M且尚未标记的边连到xi .现在,顶点xi 是被扫描的。

如果不存在被标记但未被扫描的顶点,则转到4)。

4)如果在步骤3)没有新的标记被标到Y的顶点上,则停止。

否则,转到5)。

5)当存在Y被标记但未被扫描的顶点时,选择Y的一个被标记但未被扫描的顶点,比如yi,用(yi)标记X的顶点,这些顶点被属于M且尚未标记的边连到yi.现在,顶点yi是被扫描的。

如果不存在被标记但未被扫描的顶点,则转到2)。

也可以叙述为:
[ZZ]匈牙利算法
关键在于匈牙利算法的递归过程中有很多重复计算的节点,而且这种重复无法避免,他不能向动态规划一样找到一个“序”将递归改为递推。

算法中的几个术语说明:
1。

二部图:
如果图G=(V,E)的顶点集何V可分为两个集合X,Y,且满足X∪Y = V, X∩Y=Φ,则G称为二
部图;
图G的边集用E(G)表示,点集用V(G)表示。

2。

匹配:
设M是E(G)的一个子集,如果M中任意两条边在G中均不邻接,则称M是G的一个匹配。

M中的
—条边的两个端点叫做在M是配对的。

3。

饱和与非饱和:
若匹配M的某条边与顶点v关联,则称M饱和顶点v,并且称v是M-饱和的,否则称v 是M-不
饱和的。

4。

交互道:
若M是二分图G=(V,E)的一个匹配。

设从图G中的一个顶点到另一个顶点存在一条道路,这条道路是由属于M的边和不属于M的边交替出现组成的,则称这条道路为交互道。

5。

可增广道路:
若一交互道的两端点为关于M非饱和顶点时,则称这条交互道是可增广道路。

显然,一条边的两端点非饱和,则这条边也是可增广道路。

6。

最大匹配:
如果M是一匹配,而不存在其它匹配M',使得|M'|>|M|,则称M是最大匹配。

其中|M|表

匹配M的边数。

7。

对称差:
A,B是两个集合,定义
A⊕B = (A∪B)\(A∩B)
则A⊕B称为A和B的对称差。

定理:M为G的最大匹配的充要条件是G中不存在可增广道路。

Hall定理:对于二部图G,存在一个匹配M,使得X的所有顶点关于M饱和的充要条件是:对于
X的任意一个子集A,和A邻接的点集为T(A),恒有:|T(A)| >= |A|
匈牙利算法是基于Hall定理中充分性证明的思想,其基本步骤为:
1。

任给初始匹配M;
2。

若X已饱和则结束,否则进行第3步;
3。

在X中找到一个非饱和顶点x0,作
V1 ← {x0}, V2 ← Φ
4。

若T(V1) = V2则因为无法匹配而停止,否则任选一点y ∈T(V1)\V2;
5。

若y已饱和则转6,否则做一条从x0 →y的可增广道路P,M←M⊕E(P),转2;
6。

由于y已饱和,所以M中有一条边(y,z),作V1 ← V1 ∪{z}, V2 ← V2 ∪{y},转4;。

相关文档
最新文档