题意:给定N个点,M条边,M >= N-1。已知M条边都有一个权值,已知前N-1边能构成一颗N个节点生成树,现问通过修改这些边的权值使得最小生成树为前N条边的最小改动总和为多少?

分析:由于计算的最小改动且为最小生成树则显然前N-1条边肯定权值都减少,后面的边权值都增加。由于选择的边为前N-1得到最小生成树,因此首先将N-1条边构图,然后对后面的每一条边,那么这条边所构成的环中,有任意一条边的a与该边b,设原始权重为w[a],w[b],改变量为d[a],w[b],则有w[a] - d[a] <= w[b] + d[b],移项后有w[a] - w[b] <= d[a] + d[b],而我们要求的 d[] 数组的和值的最小值。可以将所有的 d[x] 看作是x节点(边)的权值,则此题相当于给每个节点(边)分配一个权值,使得满足所有环中的不等式,也就是求一个最小权值匹配,其对偶问题就是构图之后的最大权值匹配问题,可行标的值就是需要分配的权值。本题有一个隐含的条件就是d[i] + d[j] >= 0表现在图中就是每个点对之间连了一条权值为0的边,这样才能够保证求出来的值都是正值。

简要分析其原理:首先最大权值匹配算法的初始化就是选择的最大的边设定可行标,且算法在始终不会改变已经匹配边的左右可行标之和的情况下,不停的扩充权值更小的边进入子图,因此其最后得到的最大匹配一定能够保证所有的边左右端点可行标之和大于等于该边权值。其次,如果一个匹配不是最大匹配,那么既然存在最大匹配那么说明肯定有某条本应该在最大匹配中的边没有加入到子图中且该边的左右端点可行标之和小于该边的权值,否则与假设矛盾。

  1. #include <cstdlib>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. using namespace std;
  6.  
  7. const int N = ;
  8. const int M = ;
  9. const int inf = 0x3f3f3f3f;
  10. int cn[N][N]; // 原图中的边
  11. int w[M][M]; // 二分图中边的关系
  12. int lx[M], ly[M];
  13. char vx[M], vy[M];
  14. int match[M];
  15. int slack[M];
  16. int n, m, nm;
  17. struct Edge {
  18. int a, b, c;
  19. }e[M];
  20.  
  21. bool dfs(int p, int u, int id) {
  22. for (int i = ; i <= n; ++i) {
  23. if (i == p) continue;
  24. if (cn[u][i] == id) return true;
  25. if (cn[u][i] != && dfs(u, i, id)) {
  26. w[cn[u][i]][id-(n-)] = max(e[cn[u][i]].c - e[id].c, );
  27. return true;
  28. }
  29. }
  30. return false;
  31. }
  32.  
  33. bool path(int u) {
  34. vx[u] = ;
  35. for (int i = ; i <= nm; ++i) {
  36. if (vy[i]) continue;
  37. if (lx[u] + ly[i] == w[u][i]) {
  38. vy[i] = ;
  39. if (match[i] == - || path(match[i])) {
  40. match[i] = u;
  41. return true;
  42. }
  43. } else {
  44. slack[i] = min(slack[i], lx[u]+ly[i]-w[u][i]);
  45. }
  46. }
  47. return false;
  48. }
  49.  
  50. void KM() {
  51. memset(match, 0xff, sizeof (match));
  52. memset(ly, , sizeof (ly));
  53. memset(lx, 0x80, sizeof (lx));
  54. for (int i = ; i <= nm; ++i) {
  55. for (int j = ; j <= nm; ++j) {
  56. lx[i] = max(lx[i], w[i][j]);
  57. }
  58. }
  59. for (int i = ; i <= nm; ++i) {
  60. int cnt = ;
  61. while () {
  62. memset(slack, 0x3f, sizeof (slack));
  63. memset(vx, , sizeof (vx));
  64. memset(vy, , sizeof (vy));
  65. if (path(i)) break;
  66. int d = inf;
  67. for (int j = ; j <= nm; ++j) if (!vy[j]) d = min(d, slack[j]);
  68. for (int j = ; j <= nm; ++j) if (vx[j]) lx[j] -= d;
  69. for (int j = ; j <= nm; ++j) {
  70. if (vy[j]) ly[j] += d;
  71. else slack[j] -= d;
  72. }
  73. }
  74. }
  75. }
  76.  
  77. int main() {
  78. int T, a, b, c;
  79. scanf("%d", &T);
  80. while (T--) {
  81. scanf("%d %d", &n, &m);
  82. memset(cn, , sizeof (cn));
  83. memset(w, , sizeof (w));
  84. for (int i = ; i <= m; ++i) {
  85. scanf("%d %d %d", &a, &b, &c);
  86. if (i < n) cn[a][b] = cn[b][a] = i;
  87. e[i].a = a, e[i].b = b, e[i].c = c;
  88. }
  89. for (int i = n; i <= m; ++i) {
  90. cn[e[i].b][e[i].a] = i;
  91. dfs(, e[i].a, i);
  92. cn[e[i].b][e[i].a] = ;
  93. }
  94. nm = max(n-, m-(n-));
  95. KM();
  96. for (int i = ; i < n; ++i) printf("%d\n", e[i].c-lx[i]);
  97. for (int i = ; i <= m-(n-); ++i) printf("%d\n", e[i+n-].c+ly[i]);
  98. }
  99. return ;
  100. }

ZOJ-2342 Roads 二分图最小权值覆盖的更多相关文章

  1. HDU 1853 Cyclic Tour[有向环最小权值覆盖]

    Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others)Total ...

  2. POJ 2195 Going Home 【二分图最小权值匹配】

    传送门:http://poj.org/problem?id=2195 Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submis ...

  3. HDU 3488 Tour(最小费用流:有向环最小权值覆盖)

    http://acm.hdu.edu.cn/showproblem.php?pid=3488 题意: 给出n个点和m条边,每条边有距离,把这n个点分成1个或多个环,且每个点只能在一个环中,保证有解. ...

  4. Tour HDU - 3488 有向环最小权值覆盖 费用流

    http://acm.hdu.edu.cn/showproblem.php?pid=3488 给一个无源汇的,带有边权的有向图 让你找出一个最小的哈密顿回路 可以用KM算法写,但是费用流也行 思路 1 ...

  5. POJ-2195 Going Home---KM算法求最小权值匹配(存负边)

    题目链接: https://vjudge.net/problem/POJ-2195 题目大意: 给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致.man每移动一格 ...

  6. UVa 1349 (二分图最小权完美匹配) Optimal Bus Route Design

    题意: 给出一个有向带权图,找到若干个圈,使得每个点恰好属于一个圈.而且这些圈所有边的权值之和最小. 分析: 每个点恰好属于一个有向圈 就等价于 每个点都有唯一后继. 所以把每个点i拆成两个点,Xi  ...

  7. POJ 3565 Ants 【最小权值匹配应用】

    传送门:http://poj.org/problem?id=3565 Ants Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: ...

  8. hdu 1853 Cyclic Tour (二分匹配KM最小权值 或 最小费用最大流)

    Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others)Total ...

  9. 紫书 例题11-10 UVa 1349 (二分图最小权完美匹配)

    二分图网络流做法 (1)最大基数匹配.源点到每一个X节点连一条容量为1的弧, 每一个Y节点连一条容量为1的弧, 然后每条有向 边连一条弧, 容量为1, 然后跑一遍最大流即可, 最大流即是最大匹配对数 ...

随机推荐

  1. c# 定时执行python脚本

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  2. Yeoman

    安装Yeoman之前,确认安装好Node.js和npm. sudo npm install --global yo 然后查看软件版本 yo --version && bower --v ...

  3. ACM题目————A除以B

    本题要求计算A/B,其中A是不超过1000位的正整数,B是1位正整数.你需要输出商数Q和余数R,使得A = B * Q + R成立. 输入格式: 输入在1行中依次给出A和B,中间以1空格分隔. 输出格 ...

  4. js中的各种获取日期

    JS中获取当前时间点前一天时间 var date=new Date(); var dat_year=date.getYear(); var dat_month=date.getMonth(); var ...

  5. 安装python-devel 在升级到python2.7之后

    分别执行如下命令: # yum update # yum install centos-release-SCL # yum search all python27 在搜索出的列表中发现python27 ...

  6. 一种奇特的DEDE隐藏后门办法

    转自:http://www.91ri.org/6462.html   一种奇特的DEDE隐藏后门办法 单位某站用的dedecms,今天被某黑阔getshell了,提交到了wooyun. 为了还原黑阔入 ...

  7. log4j: 不同的类使用不同的日志

    有时候会需要某些功能中使用独立的日志文件,以下为代码示例. public final static String LOGGER_NAME = "MyFunction"; priva ...

  8. 掌握Tiles 框架 (一)---Tiles入门和Tiles 框架和体系结构

    掌握Tiles 框架 (一)---Tiles入门和Tiles 框架和体系结构 入门 本教程所讲述的内容 本教程讲述如何使用 Tiles 框架来创建可重用的表示组件.(在最初创建它时,Tiles 框架被 ...

  9. Python3基础 ,= 一个等式给多个变量赋值

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  10. CentOS 7.0安装配置LAMP服务器(Apache+PHP+MariaDB)

    CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop firewalld.service #停止fir ...