二分图匹配相关算法

二分图匹配相关算法二分图匈牙利算法二分图匈牙利算法二分图匈牙利算法这里简单记录下二分图匹配的相关算法 供自己使用 如果各位游客看到觉得浪费时间 便请移步 文章全为个人模板记录匈牙利算法匈牙利算法研究的是二分图的最大匹配 是对给定的二分图求得最大的满足条件的匹配数 匹配对 其算法思想是利用 Berge 定理和 Hall 定理将初始匹配通过迭代寻找增广路径得到最大匹配 每次迭代得到的匹配大小加 1 具体迭代实现有 DFS

二 分 图 匈 牙 利 算 法 二分图匈牙利算法
这里简单记录下二分图匹配的相关算法,供自己使用。如果各位游客看到觉得浪费时间,便请移步,文章全为个人模板记录

  • 匈牙利算法
    匈牙利算法研究的是二分图的最大匹配,是对给定的二分图求得最大的满足条件的匹配数,匹配对。其算法思想是利用Berge定理和Hall定理将初始匹配通过迭代寻找增广路径得到最大匹配,每次迭代得到的匹配大小加1
    具体迭代实现有DFS和BFS两种。下面贴上DFS版的cpp写法
    时间复杂度O( n × m n \times m n×m)


//匈牙利算法 时间复杂度为O(n*m) #include "bits/sdtc++.h" #define MAX 1003 using namespace std; int n,m,e; int map[MAX][MAX]; int vis[MAX]; int nextLeft[MAX],nextRight[MAX];//nextLeft[]是左部点匹配到右边的点,同理nextRight int fa[MAX]; bool Find(int u) { 
    //是DFS迭代寻找增广路径,(还有个形象的说法就是腾地) for (int i = 1; i<= m; i++) { 
    if (map[u][i] && !vis[i]) { 
    vis[i] = 1; if (-1==nextRight[i] || Find(nextRight[i])) { 
    //“腾地”,如果,nextRight[i]还未匹配右边的点,或者nextRight[i]还有增广路径可走有其他点可以与其匹配就“腾地” nextRight[i] = u; nextLeft[u] = i; return true; } } } return false; } int MaxMatch() { 
    //最大匹配,在主函数中直接调用MaxMatch(),返回最大匹配数。 int ans(0); memset(nextLeft,-1,sizeof(nextLeft)); memset(nextRight,-1,sizeof(nextRight)); for (int i = 1; i<=n; i++) { 
    if (-1 == nextLeft[i]) { 
    // { 
    memset(vis,0,sizeof(vis)); if (Find(i)) ans++; } } return ans; } int main(int argc,char *argv[]) { 
    scanf("%d%d%d", &n,&m,&e); for (int i = 1; i <= e; i++) { 
    int u,v; scanf("%d%d", &u,&v); if (u>=1&&u<=n&&v>=1&&v<=m) { 
    map[u][v] = 1; } } printf("%d\n", MaxMatch()); return 0; } 

H o p c r o f t − K a r p 算 法 Hopcroft-Karp 算法 HopcroftKarp
该算法也是求二分图最大匹配的,不过相对与匈牙利算法而言,效率更高,时间复杂度更优秀,但缺点是书写麻烦。

  • Hopcroft-Karp 算法
    HK算法相比匈牙利算法高效的地方在于寻找增广路上,匈牙利算法是每次迭代的时候寻找一条增广路,而HK算法是先寻找一个增广路集合,在一次搜索中寻找多条不相交的增广路径,形成极大增广路径集。
    HK算法的复杂度 O( n 1 2 × m n^{\frac{1}{2}}\times m n21×m)
    主函数直接调用MaxMatch().


//Hopcroft-Karp 算法 时间复杂度为O(n^(1/2)*m) //该算法是对匈牙利算法的优化,利用匈牙利算法一次只能找到一条增广路径, //Hopcroft-Karp就提出一次找到多条不相交的增广路径(不相交就是没有公共点和公共边的增广路径),称为增广路集 //然后根据这些增广路径添加多个匹配,并逐渐增加增广路径集中增广路径的长度。 #include "bits/stdc++.h" #define MAX 3003 #define INF 0x3f3f3f3f using namespace std; int nextLeft[MAX],nextRight[MAX]; //nextLeft[MAX]是左集合匹配右集合的点,同理nextRight也是 int dLeft[MAX],dRight[MAX]; //dLeft[MAX],dRight[MAX]是增广路径长度,或者说BFS深度 int dx[MAX],dy[MAX]; int map[MAX][MAX]; //map[MAX][MAX]存图 int nx,ny; //nx,ny分别是左集合点个数,右集合点个数 int dis; int vis[MAX]; //标记数组. bool searchPath() { 
    //寻找增广路径集,其增广路径集中每条增广路径长度一样 queue<int>Q; dis = INF; memset(dLeft,-1,sizeof(dLeft)); memset(dRight,-1,sizeof(dRight)); for (int i = 1;i <= nx; i++) { 
    //在BFS中宽度搜索 if (-1 == nextLeft[i]) { 
    //将未遍历的节点 入队 并初始化次节点距离为0  Q.push(i); dLeft[i] = 0; } } while (!Q.empty()) { 
    //广度搜索增广路径 int u = Q.front(); Q.pop(); if (dLeft[u] > dis) break; for (int v = 1; v <= ny; v++) { 
    //取右侧节点  if (map[u][v] && -1==dRight[v]) { 
    //右侧节点的增广路径的距离 dRight[v] = dLeft[u]+1; //v对应的距离 为u对应距离加1 if (-1 == nextRight[v]) dis = dRight[v]; else { 
    dLeft[nextRight[v]] = dRight[v]+1; Q.push(nextRight[v]); } } } } return dis != INF; } bool Find(int u) { 
    //Find函数,对增广路径集进行增广。 for (int v = 1; v <= ny; v++) { 
    if (!vis[v] && map[u][v] && dRight[v] == dLeft[u]+1) { 
    vis[v] = 1; if (nextRight[v] != -1 && dRight[v] == dis) continue; if (-1 == nextRight[v] || Find(nextRight[v])) { 
    nextRight[v] = u;nextLeft[u] = v; return true; } } } return false; } int MaxMatch() { 
    int ans(0); memset(nextRight,-1,sizeof(nextRight)); memset(nextLeft,-1,sizeof(nextLeft)); while(searchPath()) { 
    //不断进行增广路径集的操作,其增广路径也不断增长。 memset(vis,0,sizeof(vis)); for (int i = 1; i <= nx; i++) { 
    if (-1 == nextLeft[i]) { 
    if (Find(i)) ans++; } } } return ans; } int main(int argc,char *argv[]) { 
    // int n,m,e; int e; scanf("%d%d%d", &nx,&ny,&e); for (int i = 1; i <= e; i++) { 
    int u,v; scanf("%d%d", &u,&v); if (u>=1&&u<=nx&&v>=1&&v<=ny) { 
    map[u][v] = 1; } } printf("%d\n", MaxMatch()); return 0; } 

二 分 图 多 重 匹 配 二分图多重匹配

  • 多重匹配算法
    二分图普通的匹配是一对一的匹配,左集合X和右集合Y是一一对应的关系,如果允许Y集合中的一个元素和集合X中的多个元素匹配(通常有一个最大限制n),但是X集合中的一个元素只能和Y集合的一个元素匹配,这就是二分图多重匹配的模型
  • 算法步骤
    在构造二分图的多重匹配模型时,由于集合Y中的一个元素可以同时匹配集合X中的多个元素。所以,匈牙利算法中的cy[MAX]应该更换为一个二维数组 cy[MAX][MAX]。cy[i][j],表示与元素 y i y_i yi匹配的第j个元素,同时用vcy[i]来记录与元素 y i y_i yi匹配的元素的数量。
    二分查找可以构成多重匹配的limit值。在主函数main()方法中进行二分查找,并调用MulMatch()就可以得到limit值。

/*二分图多重匹配算法*/ #include "bits/stdc++.h" #define MAX 1001 int bmap[MAX][MAX]; int vis[MAX]; int nx,ny; int vcy[MAX]; int cy[MAX][MAX]; int limit; int left;int right; bool Find(int u) { 
    for (int i = 1; i <= ny; i++) { 
    if (bmap[u][i] && !vis[i]) { 
    vis[u] = 1; if (vcy[i] < limit) { 
    cy[i][vcy[i]++] = u; return true; } for (int j = 1; j <= vcy[i]; j++) { 
    if (Find(cy[i][j])) { 
    cy[i][j] = u; return true; } } } } return false; } bool MulMatch() { 
    memset(vcy,0,sizeof(vcy)); for (int i = 1; i <= nx; i++) { 
    memset(vis,0,sizeof(vis)); if (!Find(i)) return false; } return true; } using namespace std; int main(int argc,char *argv[]) { 
    /* 根据题意建图... */ left = 0, right = nx; //二分查找 while (left < right) { 
    limit = (left+right)/2; if (MulMatch()) right = limit; else left = limit+1; } /* 根据题意输出... */ return 0; } 

二 分 图 最 佳 匹 配 二分图最佳匹配

  • Kuhn-Munkres算法
/*二分图最佳匹配算法*/ /*Kuhn-Munkres算法*/ /*hdu 2255 例题*/ #include "bits/stdc++.h" #define MAX 1001 #define INF 0x3f3f3f3f using namespace std; int bmap[MAX][MAX]; int visx[MAX],visy[MAX],cx[MAX],cy[MAX]; int nextLeft[MAX],nextRight[MAX]; int w[MAX][MAX]; int n,m,ans; //n左m右 bool Find(int x) { 
    visx[x] = 1; for (int i = 1; i <= m; i++) { 
    if (!visy[i] && (cx[x]+cy[i] == w[x][i])) { 
    visy[i] = 1; if (!nextRight[i] || Find(nextRight[i])) { 
    nextRight[i] = x; nextLeft[x] = i; return true; } } } return false; } int kuhnMunkres() { 
    for (int i = 1; i <= n; i++) { 
    while (1) { 
    int D = INF; memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if (Find(i)) break; for (int j = 1; j <= n; j++) { 
    if (visx[j]) for (int k = 1; k <= m; k++) if (!visy[k]) D = min(D,cx[j]+cy[k]-w[j][k]); } if (D == INF) return -1; for (int j = 1; j <= n; j++) if (visx[j]) cx[j] -= D; for (int j = 1; j <= m; j++) if (visy[j]) cy[j] += D; } } ans = 0; for (int i = 1; i <= m; i++) ans += w[nextRight[i]][i]; return ans; } int main(int argc, char const *argv[]) { 
    while (scanf("%d", &n)!=EOF) { 
    m = n; memset(cy,0,sizeof(cy)); memset(cx,0,sizeof(cx)); memset(w,0,sizeof(w)); for (int i = 1; i <= n; i++) { 
    int D = 0; for (int j = 1; j <= m; j++) { 
    scanf("%d", &w[i][j]); D = max(D,w[i][j]); } cx[i] = D; } memset(nextLeft,0,sizeof(nextLeft)); memset(nextRight,0,sizeof(nextRight)); int ANS = kuhnMunkres(); printf("%d\n", ANS); } return 0; } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231410.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql 组合索引 前缀_Mysql中的联合索引、前缀索引、覆盖索引[通俗易懂]

    mysql 组合索引 前缀_Mysql中的联合索引、前缀索引、覆盖索引[通俗易懂]索引索引是一种特殊的文件,它们包含着对数据表里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。联合索引又名复合索引,由两个或多个列的索引。它规定了mysql从左到右地使用索引字段,对字段的顺序有一定要求。一个查询可以只使用索引中的一部分,更准确地说是最左侧部分(最左优先)。如索引是keyindex(a,b,c).可以支持a|a,b|a,b,c…

    2022年5月23日
    41
  • 关于CultureInfo

    关于CultureInfoCultureInfo提供有关特定区域性的信息(如区域性的名称、书写系统和使用的日历)以及如何设置日期和排序字符串的格式。在ASP.NET2.0中提供多语言转换和多样式主题转换功能中,经常用到CultureInfo.可用CultureInfo.Name获得区域性名称,CultureInfo的默认是.NETFramework的安装版本。改变CultureInfo值方法为可在Global….

    2022年6月19日
    29
  • Owasp top10 小结[通俗易懂]

    Owasp top10 小结[通俗易懂]Owasptop101.SQL注入原理:web应用程序对用户输入的数据合法性没有过滤或者是判断,前端传入的参数是攻击者可以控制,并且参数带入数据库的查询,攻击者可以通过恶意的sql语句来实现对数据库的任意操作。2.失效的身份认证和会话管理原理:在开发web应用程序时,开发人员往往只关注Web应用程序所需的功能,所以常常会建立自定义的认证和会话方案。但是要正确的实现这些方案却是很难的。结果就在退出,密码管理,超时,密码找回,账户更新等方面存在漏洞。危害:由于存在以上的漏洞,恶意用户可能会窃取

    2022年5月28日
    78
  • 计算机审计学总结,审计实务实验报告总结审计实训实验报告计算机审计实验总结.docx…

    计算机审计学总结,审计实务实验报告总结审计实训实验报告计算机审计实验总结.docx…

    2021年11月27日
    42
  • Json详解以及fastjson使用教程[通俗易懂]

    Json是一种轻量级的数据交换格式,采用一种“键:值”对的文本格式来存储和表示数据,在系统交换数据过程中常常被使用,是一种理想的数据交换语言。在使用Java做Web开发时,不可避免的会遇到Json的使用。下面我们就简单讲一下Json的使用以及fastjson.jar包的使用。一:JSON形式与语法1.1:JSON对象我们先来看以下数据:{ "ID":1001, "name"…

    2022年4月10日
    178
  • Jquery Ajax 跨域调用asmx类型 WebService范例

    Jquery Ajax 跨域调用asmx类型 WebService范例Ajax在Web2.0时代起着非常重要的作用,然而有时因为同源策略(SOP)(俗称:跨域问题(crossdomain))它的作用会受到限制。在本文中,将学习如何克服合作限制。本文以asmx方式搭建webservice作为测试用后端,给出完整的前后端调用解决方案、范例代码。

    2022年6月3日
    42

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号