在看这道题之前,我们先来了解一下什么是二分图及与二分图匹配的相关概念及基础知识。
基础知识
故名思义,二分图本质上还是由点和边构成的数据结构,与之不同的是,二分图相当于把一张图分成了两个部分,也就是两个部。部与部之间的点没有边相连,以下的几个图都可以算作二分图:
(图中的箭头无意义,并不代表有向边)
现在来简单说一下匹配和最大匹配(因为只涉及匈牙利算法,所以不讲其他杂七杂八的东西。最小点覆盖什么的以后再讲)
简单来说匹配就是从二分图中选出一些边,这些边没有共同的顶点。这些边组成的边集就叫做这个二分图中的一个边集。下面是一个例子,红色边便是匹配:
最大匹配就是匹配中边数最大的一个匹配。如图为上图的一个最大匹配(注意!最大匹配并不是唯一的)
关于匈牙利算法,还有一个重要的概念,便是增广路。增广路在各种算法中都有很大的作用。这里只讲解一下其最基本的一些概念。
增广路的意义便是选取一个不在任何匹配中的一条边作为起点,再选取一条与它相邻的匹配中的一条边,下下一条边又是一条与下一条边相邻的边的不在匹配中的一条边。连在一起交错进行终点不为匹配中的边便是一条增广路。(相信你已经看懵了,下面便给出流程来)
这是一个二分图的匹配,
从任意一个顶点开始进行增广路后:
(x2,y1)不在匹配中,作为起点。所以整个增广路就为:(x2,y1)-(y1,x1)-(x1,y3)-(y3,x4)-(x4,y2)。
绿色边为不在匹配中的边。现在我们将绿色边转为红色边,红色边转为绿色边:
发现形成了一个新的匹配。发现无法再找到新的增广路,那么这些红色边便是最大匹配。
在我们程序的实现中,无法找到增广路后,当前匹配便是最大匹配。
算法部分
先给出主要的代码:
bool dfs(int u) {//dfs用来判断从当前节点出发有没有新的可覆盖的点
for(int i=0,v;i<G[u].size();i++) {
v=G[u][i];
if(vis[v]) continue;
vis[v]=1;
if( !match[v] || dfs( match[v] )) {//当前节点没有被匹配,或者被这个节点匹配的点可以匹配出去,则修改匹配
match[v]=u;
return 1;
}
}
return 0;
}
int hungary() {
int ans=0;
for(int i=1;i<=n;i++) {
memset(vis,0,sizeof(vis));//当前节点可继续匹配,则增广路中可以延伸,答案加一
if(dfs(i)) ans++;
}
return ans;
}
标签:二分,一条,匹配,最大,增广,题解,算法 来源: https://blog.csdn.net/weixin_44049566/article/details/89355256
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。