二分图算法包括 匈牙利算法 与 KM算法。

匈牙利算法

在这里写上模板。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063

  1. #include<stdio.h>
  2. #include<string.h>
  3. #define mem(a, b) memset(a, b, sizeof(a))
  4.  
  5. int head[], cnt;
  6. int k, m, n; //k为组合数,m为女生人数,n为男生人数
  7. int used[], master[];
  8.  
  9. struct Edge
  10. {
  11. int to, next;
  12. }edge[];
  13.  
  14. void add(int a, int b)
  15. {
  16. edge[++ cnt].to = b;
  17. edge[cnt].next = head[a];
  18. head[a] = cnt;
  19. }
  20.  
  21. int find(int x)
  22. {
  23. for(int i = head[x]; i != -; i = edge[i].next)
  24. {
  25. int to = edge[i].to;
  26. if(used[to] == -)
  27. {
  28. used[to] = ;
  29. if(master[to] == - || find(master[to]))
  30. {
  31. master[to] = x;
  32. return ;
  33. }
  34. }
  35. }
  36. return ;
  37. }
  38.  
  39. int main()
  40. {
  41. int ans;
  42. while(scanf("%d", &k)!=EOF)
  43. {
  44. if(k == )
  45. break;
  46. cnt = ans = ;
  47. mem(head, -), mem(master, -);
  48. scanf("%d%d", &m, &n);
  49. for(int i = ; i <= k; i ++)
  50. {
  51. int a, b;
  52. scanf("%d%d", &a, &b);
  53. add(a, b);
  54. }
  55. for(int i = ; i <= m; i ++)
  56. {
  57. mem(used, -);
  58. if(find(i))
  59. ans ++;
  60. }
  61. printf("%d\n", ans);
  62. }
  63. return ;
  64. }

KM算法

KM算法是用来解决带权问题的最大匹配. (用邻接矩阵实现, 首先因为带权的话, X部,Y部都有边,一般是稠密图,其次邻接表并不好实现)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255

  1. #include<stdio.h>
  2. #include<string.h>
  3. #define mem(a, b) memset(a, b, sizeof(a))
  4. const int inf = 0x3f3f3f3f;
  5.  
  6. int n, nx, ny;
  7. int lx[], ly[];//x部点的值,y部点的值
  8. int visx[], visy[];//标记x,y部的点是否在相等子图中,用于更新点的值
  9. int slack[];//松弛量, 用于优化KM算法 优化后复杂度为 n^3
  10. int goal[], weight[][];
  11.  
  12. int find(int x)//新增的x部的点
  13. {
  14. visx[x] = ;
  15. for(int j = ; j <= ny; j ++)
  16. {
  17. if(!visy[j])
  18. {
  19. int t = lx[x] + ly[j] - weight[x][j]; //匹配到的标准是 x部 + y部点的值等于边权值
  20. if(t == )
  21. {
  22. visy[j] = ;
  23. if(goal[j] == - || find(goal[j]))
  24. {
  25. goal[j] = x;
  26. return ;
  27. }
  28. }
  29. else if(slack[j] > t)//没被匹配到的点记录最小slack
  30. slack[j] = t;
  31. }
  32. }
  33. return ;
  34. }
  35.  
  36. int km()
  37. {
  38. mem(ly, ); //y部的初始化为0
  39. mem(lx, );
  40. mem(goal, -);
  41. for(int i = ; i <= nx; i ++)//x部点的值初始化为与y部相连的最大值
  42. for(int j = ; j <= ny; j ++)
  43. if(weight[i][j] > lx[i])
  44. lx[i] = weight[i][j];
  45. for(int i = ; i <= nx; i ++)
  46. {//每次扩充一个点, 都要重新初始化y部的slack,因为需要在相等子图中找到最大的权值匹配
  47. for(int j = ; j <= ny; j ++)
  48. slack[j] = inf;
  49. while()
  50. {
  51. mem(visx, );
  52. mem(visy, );
  53. if(find(i)) //如果当前子图可以匹配的到就跳出, 扩充下一个x部的点继续匹配
  54. break;
  55. //如果当前子图没匹配到,就用slack更新值再循环while寻找当前子图的最大权值匹配
  56. int d = inf;
  57. for(int j = ; j <= ny; j ++)
  58. if(!visy[j] && d > slack[j])
  59. d = slack[j];//找到一个最小的差值 在未尝试匹配的y部中找
  60. for(int j = ; j <= ny; j ++)
  61. if(!visy[j])
  62. slack[j] -= d;
  63. for(int j = ; j <= n; j ++)//参与匹配的点x部的减 ,y部的加
  64. {
  65. if(visy[j])
  66. ly[j] += d;
  67. if(visx[j])
  68. lx[j] -= d;
  69. }
  70. }
  71. }
  72. int ans = ;
  73. for(int j = ; j <= ny; j ++)
  74. if(goal[j] != -)
  75. ans += weight[goal[j]][j];
  76. return ans;
  77. }
  78.  
  79. int main()
  80. {
  81. while(scanf("%d", &n)!=EOF)
  82. {
  83. nx = n, ny = n;
  84. for(int i = ; i <= n; i ++)
  85. for(int j = ; j <= n; j ++)
  86. scanf("%d", &weight[i][j]);
  87. int ans = km();
  88. printf("%d\n", ans);
  89. }
  90. return ;
  91. }

对于KM算法求最小匹配, 只需要在最大匹配的模板上改动几个地方即可,

在存图时将边权全记为负边权,那么会发现在对lx顶标记录最大值的时候实际上是绝对值最小的负值,也就是最小匹配了. 将lx[]数组初始化为-inf,然后对于最后的答案取负号就可以了.

二分图的最大匹配以及带权匹配【匈牙利算法+KM算法】的更多相关文章

  1. 奔小康赚大钱---hdu2255(最大带权匹配)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 带权匹配问题的模板: 运用KM算法: #include<stdio.h> #incl ...

  2. hdu3722Card Game(KM最大带权匹配)

    题目请戳这里 题目大意:给n个字符串,再给一个n的排列:p1,p2....pn.然后将第i个字符串贴到第pi个字符串后面,然后形成一个环.pi的首字符和第i个字符串的末尾字符就相邻,如果这2个字符相等 ...

  3. HDU2255 奔小康赚小钱钱(二分图-最大带权匹配)

    传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子 ...

  4. POJ3565带权匹配——km算法

    题目:http://poj.org/problem?id=3565 神奇结论:当总边权最小时,任意两条边不相交! 转化为求二分图带权最小匹配. 可以用费用流做.但这里学一下km算法. https:// ...

  5. HDU - 2255 奔小康赚大钱(最大带权匹配)

     Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓, ...

  6. UVA - 10004 Bicoloring(判断二分图——交叉染色法 / 带权并查集)

    d.给定一个图,判断是不是二分图. s.可以交叉染色,就是二分图:否则,不是. 另外,此题中的图是强连通图,即任意两点可达,从而dfs方法从一个点出发就能遍历整个图了. 如果不能保证从一个点出发可以遍 ...

  7. 【二分图最大权完美匹配】【KM算法】【转】

    [文章详解出处]https://www.cnblogs.com/wenruo/p/5264235.html KM算法是用来求二分图最大权完美匹配的.[也就算之前的匈牙利算法求二分最大匹配的变种??] ...

  8. [C++]多源最短路径(带权有向图):【Floyd算法(动态规划法)】 VS n*Dijkstra算法(贪心算法)

    1 Floyd算法 1.1 解决问题/提出背景 多源最短路径(带权有向图中,求每一对顶点之间的最短路径) 方案一:弗洛伊德(Floyd算法)算法 算法思想:动态规划法 时间复杂度:O(n^3) 形式上 ...

  9. 运动员最佳匹配问题(km算法)

    洛谷传送门 带权二分图最大权完美匹配. 裸的km算法. 注意开long long. #include <cstdio> #include <cstring> #include ...

随机推荐

  1. learning gcc __BEGIN_DECLS and __END_DECLS

    __BEGIN_DECLS and  __END_DECLS  be use for mix C and C++

  2. [JSOI 2016] 最佳团体(树形背包+01分数规划)

    4753: [Jsoi2016]最佳团体 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2003  Solved: 790[Submit][Statu ...

  3. ImageSharp跨平台图片处理

    添加nuget引用 SixLabors.ImageSharp 和SixLabors.ImageSharp.Drawing 暂时只实现了缩略图..<pre>using SixLabors.I ...

  4. codeforces#1159D. The minimal unique substring(打表找规律+构造)

    题目链接: https://codeforces.com/contest/1159/problem/D 题意: 构造一个长度为$n$的$01$串,最小特殊连续字串的长度为$k$ 也就是,存在最小的$k ...

  5. HTML容器标签和文本标签

    html中的容器级标签和文本级标签,css中的块级元素和行内元素是我们常常拿来比较的四个名词(行内块级暂时先不考虑).注:如果标签嵌套错误,可能会发生浏览器解析错误的情况,只是针对嵌套做的这个. 容器 ...

  6. PL/SQL中直接写SQL语句和用EXECUTE IMMEDIATE方法的区别

    PL/SQL中直接写SQL语句和用EXECUTE IMMEDIATE方法的区别 在PL/SQL中在执行SQL语句时可以直接写SQL或者可以把一个SQL语句拼成一个字符串,如下: select * fr ...

  7. apidoc 接口文档系统

    代码未动,文档先行.apidoc可以方便地维护接口文档.模拟响应数据.前后端分离.导出PDF文档. 特性说明 可视化编辑:支持表单界面编辑接口,不必手动编辑swagger.json 接口模拟响应:支持 ...

  8. Int和Integer(课上测试)

    截图 第一段代码: 第二段代码: 两段代码出现不同结果的原因:Integer类型的取值范围为-128至128之间,小于128的数(图1)为正确,大于128的数(图2)为错误

  9. 邻居子系统 之 状态定时器回调neigh_timer_handler

    概述 在分配邻居子系统之后,会设置定时器来处理那些需要定时器处理的状态,定时器回调函数为neigh_timer_handler:函数会根据状态机变换规则对状态进行切换,切换状态后,如果需要更新输出函数 ...

  10. CDN之Web Cache

    1. Cache 的工作方式 Web Cache 作为一种网页缓存技术,可以在用户访问网站服务器的任何一个中间网元上实现.根据 HTTP 协议的定义,在一次网页访问中,用户从客户端发出请求到网站服务器 ...