求解分配问题(二) 二分图最大匹配算法

我的前一篇文章介绍了对于分配问题的Kuhn-Munkre算法,该算法其实可以看作是邻接矩阵形式的匈牙利算法,如果更抽象地看这个算法,它可以看成是一个二分图匹配算法的变体算法,具体的说,是二分图最大权重匹配算法。我打算也把二分图最大权重匹配算法也介绍下,不过最大权重匹配算法又是基于最大匹配算法设计的,所以这篇文章先介绍二分图的最大匹配算法

二分图最大匹配问题

分配问题从图论的角度看其实是一个二分图(Bipartite Graph),就是说图中有两个点集,在各自的点集内的点互相没有连接,两个点集间的点可以连接,每个点存在多个允许的连接,如下图所示:
在这里插入图片描述

如果我们对二分图中的每个点,都确定最多只有一条连接,那么称之为该二分图的一个匹配,例如:
在这里插入图片描述
如果每个点都有一条线确定,即匹配的线数正好等于单个点集点数 n n n,那么称之为完美匹配,如下图:
在这里插入图片描述
对应于现实问题,我们当然希望尽量达到完美匹配,但是因为点的可选连线情况可能导致无论如何也达不到完美匹配,所以自然而然产生了最大匹配问题(Max-Bipartite Matching),最大可以找到多少条匹配线

用数学语言描述:

  • G = ( V , E ) G=(V,E) G=(V,E)是一个二分图, n = ∣ V ∣ n=|V| n=V m = ∣ E ∣ m=|E| m=E δ ( v ) , v ∈ V \delta(v), v\in V δ(v),vV表示一端连接到点 v v v的所有边, x e ∈ { 0 , 1 } x_e\in \{0,1\} xe{ 0,1}表示边 e e e是否被选中,则有最大匹配问题:
    m a x ∑ e ∈ E x e s . t . ∑ e ∈ δ ( v ) ≤ 1 , ∀ v ∈ V x e ∈ { 0 , 1 } , ∀ e ∈ E \begin{aligned} max\quad& \sum_{e\in E} x_e\\ s.t.\quad& \sum_{e\in \delta(v)}\leq 1,\forall v \in V \\ & x_e\in \{0,1\},\forall e \in E \\ \end{aligned} maxs.t.eE
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
人工智能关于最大二分的程序代码: #include<stdio.h> #include<string.h> main() { bool map[100][300]; int i,i1,i2,num,num1,que[300],cou,stu,match1[100],match2[300],pque,p1,now,prev[300],n; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d%d",&cou;,&stu;); memset(map,0,sizeof(map)); for(i1=0;i1<cou;i1++) { scanf("%d",&num;); for(i2=0;i2<num;i2++) { scanf("%d",&num1;); map[i1][num1-1]=true; } } num=0; memset(match1,int(-1),sizeof(match1)); memset(match2,int(-1),sizeof(match2)); for(i1=0;i1<cou;i1++) { p1=0; pque=0; for(i2=0;i2<stu;i2++) { if(map[i1][i2]) { prev[i2]=-1; que[pque++]=i2; } else prev[i2]=-2; } while(p1<pque) { now=que[p1]; if(match2[now]==-1) break; p1++; for(i2=0;i2<stu;i2++) { if(prev[i2]==-2&&map;[match2[now]][i2]) { prev[i2]=now; que[pque++]=i2; } } } if(p1==pque) continue; while(prev[now]>=0) { match1[match2[prev[now]]]=now; match2[now]=match2[prev[now]]; now=prev[now]; } match2[now]=i1; match1[i1]=now; num++; } if(num==cou) printf("YES\n"); else printf("NO\n"); } } dfs实现过程: #include<stdio.h> #include<string.h> #define MAX 100 bool map[MAX][MAX],searched[MAX]; int prev[MAX],m,n; bool dfs(int data) { int i,temp; for(i=0;i<m;i++) { if(map[data][i]&&!searched[i]) { searched[i]=true; temp=prev[i]; prev[i]=data; if(temp==-1||dfs(temp)) return true; prev[i]=temp; } } return false; } main() { int num,i,k,temp1,temp2,job; while(scanf("%d",&n)!=EOF&&n!=0) { scanf("%d%d",&m,&k); memset(map,0,sizeof(map)); memset(prev,int(-1),sizeof(prev)); memset(searched,0,sizeof(searched)); for(i=0;i<k;i++) { scanf("%d%d%d",&job;,&temp1;,&temp2;); if(temp1!=0&&temp2;!=0) map[temp1][temp2]=true; } num=0; for(i=0;i<n;i++) { memset(searched,0,sizeof(searched)); dfs(i); } for(i=0;i<m;i++) { if(prev[i]!=-1) num++; } printf("%d\n",num); } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值