题意:

     有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否是最优的,如果不是,输出一个比这个好的就行。

思路:

    大体看一下题目,很容易想到费用流直接去弄,建图也比较简单,但是费用流超时,仔细看上面的最后一句,是找到一个比当前的好就行,不用最好,这样我们可以考虑费用流的消圈,我也是今天第一次听到这个东西,研究了将近两个小时,大体明白了,明白后再反过来想想确实很简单,学东西就这样,很正常,下面说下消圈算法,消圈可以用来判断费用流的当前状态是否是最优的,大体是这样,我们先建立残余网络,就是根据题目给的信息建出残余图,如果是初学建议不要向网上很多人那样直接建立部分有用边(初学很容易不懂),我们可以这样,把所有的残余网络都补上,我写下本题的建边过程方便理解(正反边分开建立):

ss -> i  流量0 费用0  

         //因为跑完之后前面肯定是流量都用没了

i -> ss 流量c ,费用0 

         //c是这个建筑有多少人,满流的正向0,反向满c

i -> j + n 流量INF-c 费用 w

         //w是i,j的距离+1,c是建筑里人数,本来是INF,跑完后是INF-c

j+n -> i  流量c ,费用w

         //如上

j+n -> tt 流量q,费用0,

         //q是建筑的容量剩余,就是所有的-当前用了的,当前用的综合自己算出来

tt -> j+n 流量p,费用0

         //p是当前这个避难所一共用了多少容量

建图之后从重点开始跑最短路,如果没有发现负权值回路那么就是最优的,否则我们就随便找到一个负权值回路,然后把i->j的边的流量++,j->i的边的流量--,至于为什么这样我们可以这样想,首先建议现在纸上大体画一下,自己随便找一个负权值回路,然后看看特点,从终点开始跑,发现负权值回路说明正值<负值(花费),那么我们把负值的流量-1给正值得流量+1,是不是即达到了流量平衡有减少了花费呢?还有找负权值回路的时候和费用流是一样的,费用更小(最短路)同时有流量才能跑,如果还不懂就不停的画,画着画着就懂了,还有画的过程中记得去想费用流的反向费用是负的,最大流的反向流量就是正向流量的减少量,还有一点就是注意一下,找负环的时候,如果用的是Spfa的话,最后一个有可能不是环上的,这样我们就得先找到一个肯定是环上的点,这个好办,直接mark,从后往前一直找到mark过的就跳出来,当前这个肯定是环上的(不明白的话可以在纸上画几个6感觉下),具体看代码。


  1. #include<queue>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #define N_node 205
  5. #define N_edge 30000
  6. #define INF 100000000
  7. using namespace std;
  8. typedef struct
  9. {
  10. int from ,to ,cost ,flow ,next;
  11. }STAR;
  12. typedef struct
  13. {
  14. int a ,b ,c;
  15. }NODE;
  16. STAR E[N_edge];
  17. int list[N_node] ,tot;
  18. int C[N_node];//入队次数
  19. int mer[N_node];//记录路径
  20. int s_x[N_node] ,mark[N_node];
  21. int now[N_node][N_node];
  22. NODE A[N_node] ,B[N_node];
  23. void add(int a ,int b ,int c ,int d)
  24. {
  25. E[++tot].from = a;
  26. E[tot].to = b;
  27. E[tot].cost = c;
  28. E[tot].flow = d;
  29. E[tot].next = list[a];
  30. list[a] = tot;
  31. }
  32. int abss(int x)
  33. {
  34. return x > 0 ? x : -x;
  35. }
  36. bool Spfa(int s ,int n)
  37. {
  38. for(int i = 0 ;i <= n ;i ++)
  39. s_x[i] = INF;
  40. memset(mark ,0 ,sizeof(mark));
  41. memset(C ,0 ,sizeof(C));
  42. queue<int>q; q.push(s);
  43. mark[s] = C[s] = 1 ,s_x[s] = 0;
  44. int xin ,tou;
  45. memset(mer ,255 ,sizeof(mer));
  46. while(!q.empty())
  47. {
  48. tou = q.front();
  49. q.pop();
  50. mark[tou] = 0;
  51. for(int k = list[tou] ;k ;k = E[k].next)
  52. {
  53. xin = E[k].to;
  54. if(s_x[xin] > s_x[tou] + E[k].cost && E[k].flow)
  55. {
  56. s_x[xin] = s_x[tou] + E[k].cost;
  57. mer[xin] = k;
  58. if(!mark[xin])
  59. {
  60. mark[xin] = 1;
  61. q.push(xin);
  62. if(++C[xin] > n) return xin;
  63. }
  64. }
  65. }
  66. }
  67. return 0;
  68. }
  69. int main ()
  70. {
  71. int n ,m ,i ,j;
  72. int st[N_node];
  73. while(~scanf("%d %d" ,&n ,&m))
  74. {
  75. for(i = 1 ;i <= n ;i++)
  76. scanf("%d %d %d" ,&A[i].a ,&A[i].b ,&A[i].c);
  77. for(i = 1 ;i <= m ;i ++)
  78. scanf("%d %d %d" ,&B[i].a ,&B[i].b ,&B[i].c);
  79. memset(st ,0 ,sizeof(st));
  80. for(i = 1 ;i <= n ;i ++)
  81. for(j = 1 ;j <= m ;j ++)
  82. {
  83. scanf("%d" ,&now[i][j]);
  84. st[j] += now[i][j];
  85. }
  86. memset(list ,0 ,sizeof(list));
  87. tot = 1;
  88. int ss = 0 ,tt = n + m + 1;
  89. for(i = 1 ;i <= n ;i ++)
  90. add(ss ,i ,0 ,0),add(i ,ss ,0 ,A[i].c);
  91. for(i = 1 ;i <= m ;i ++)
  92. add(i + n ,tt ,0 ,B[i].c - st[i]) ,add(tt ,i + n ,0 ,st[i]);
  93. for(i = 1 ;i <= n ;i ++)
  94. for(j = 1 ;j <= m ;j ++)
  95. {
  96. add(i ,j + n ,abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1 ,INF - now[i][j]);
  97. add(j + n ,i ,-(abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1) ,now[i][j]);
  98. }
  99. int x = Spfa(tt ,tt);
  100. if(!x)
  101. {
  102. printf("OPTIMAL\n");
  103. continue;
  104. }
  105. printf("SUBOPTIMAL\n");
  106. memset(mark ,0 ,sizeof(mark));
  107. i = mer[x];
  108. while(1)//找到一个肯定在环上的点
  109. {
  110. x = E[i].to;
  111. if(mark[x]) break;
  112. mark[x] = 1;
  113. i = mer[E[i].from];
  114. }
  115. memset(mark ,0 ,sizeof(mark));
  116. for(i = mer[x] ;i + 1 ;i = mer[E[i].from])
  117. {
  118. int a = E[i].from ,b = E[i].to;
  119. if(a >= 1 && a <= n && b >= n + 1 && b <= n + m)
  120. now[a][b-n] ++;
  121. if(a >= n + 1 && a <= n + m && b >= 1 && b <= n)
  122. now[b][a-n] --;
  123. if(mark[a] && mark[b]) break;
  124. mark[a] = mark[b] = 1;
  125. }
  126. for(i = 1 ;i <= n ;i ++)
  127. for(j = 1 ;j <= m ;j ++)
  128. if(j == m) printf("%d\n" ,now[i][j]);
  129. else printf("%d " ,now[i][j]);
  130. }
  131. return 0;
  132. }

poj2175费用流消圈算法的更多相关文章

  1. POJ 2175:Evacuation Plan(费用流消圈算法)***

    http://poj.org/problem?id=2175 题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给 ...

  2. POJ 2157 Evacuation Plan [最小费用最大流][消圈算法]

    ---恢复内容开始--- 题意略. 这题在poj直接求最小费用会超时,但是题意也没说要求最优解. 根据线圈定理,如果一个跑完最费用流的残余网络中存在负权环,那么顺着这个负权环跑流量为1那么会得到更小的 ...

  3. poj 2175 费用流消圈

    题意抽象出来就是给了一个费用流的残存网络,判断该方案是不是最优方案,如果不是,还要求给出一个更优方案. 在给定残存网络上检查是否存在负环即可判断是否最优. 沿负环增广一轮即可得到更优方案. 考虑到制作 ...

  4. POJ 2175 spfa费用流消圈

    题意:给出n栋房子位置和每栋房子里面的人数,m个避难所位置和每个避难所可容纳人数.然后给出一个方案,判断该方案是否最优,如果不是求出一个更优的方案. 思路:很容易想到用最小费用流求出最优时间,在与原方 ...

  5. 【图论】Floyd消圈算法

    毫无卵用的百度百科 Definition&Solution 对于一个给定的链表,如何判定它是否存在环以及环的长度问题,可以使用Floyd消圈算法求出. 从某种意义上来讲,带环的链表在本质上是一 ...

  6. Evacuation Plan-POJ2175最小费用消圈算法

    Time Limit: 1000MS Memory Limit: 65536K Special Judge Description The City has a number of municipal ...

  7. hdu3315-My Brute(费用流 or KM算法)

    题目:My Brute Seaco是一个漂亮的妹子,喜欢玩一款名叫My Brute的游戏.情人节快到了,starvae和xingxing都想邀请妹子过节,但是妹子只能陪一个啊,于是两个人决定打一架,用 ...

  8. 最小费用流判负环消圈算法(poj2175)

    Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3384   Accepted: 888   ...

  9. POJ 2175 Evacuation Plan 费用流 负圈定理

    题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在 ...

随机推荐

  1. AI数学基础之:概率和上帝视角

    目录 简介 蒙题霍尔问题 上帝视角解决概率问题 上帝视角的好处 简介 天要下雨,娘要嫁人.虽然我们不能控制未来的走向,但是可以一定程度上预测为来事情发生的可能性.而这种可能性就叫做概率.什么是概率呢? ...

  2. CloudQuery v1.3.4 版本更新

    Hello,大家好久不见! 上一个版本(v1.3.3)发布已是春节前的事情了,此次 v1.3.4 是 CloudQuery 社区版在辛丑牛年的第一个版本发布.本次更新增加了新功能,优化了原有功能点.同 ...

  3. HiveHA机制源码分析

    hive让大数据飞了起来,不再需要专人写MR.平常我们都可以用基于thrift的任意语言来调用hive. 不过爱恨各半,hive的thrift不稳定也是出了名的.很容易就出问题,让人无计可施.唯一的办 ...

  4. Envoy 部署类型

    目录 Envoy 网络拓扑及请求流程 1. 术语 2. 网络拓扑 3. 配置 4. 更高层的架构 5. 请求流程 1. Listener TCP 接收 2. 侦听器过滤器链和网络过滤器链匹配 3.TL ...

  5. 2、Spring教程之HelloSpring

    导入Jar包 注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 . <dependency> <grou ...

  6. python之极简ATM系统示例

    """用户可登陆系统输错三次锁定账号用户可以创建新的用户名密码新用户初始账户设为0新用户可直接登陆系统用户登陆成功后可以选择业务类型用户数据可以根据业务修改输入Q随时退出 ...

  7. 基于sklearn的波士顿房价预测_线性回归学习笔记

    > 以下内容是我在学习https://blog.csdn.net/mingxiaod/article/details/85938251 教程时遇到不懂的问题自己查询并理解的笔记,由于sklear ...

  8. SpingCloud Alibaba实战(1:微服务与SpringCloud Alibaba)

    1.什么是微服务? 微服务可谓是这几年比较热门的技术,从2017开始逐渐爆火,逐渐大大小小的公司纷纷将微服务技术引入并在实际业务中落地. 微服务的概念最早是在2014年由Martin Fowler和J ...

  9. [Fundamental of Power Electronics]-PART I-6.变换器电路-6.3 变压器隔离

    6.3 变压器隔离 在许多应用场合中,期望将变压器结合到开关变换器中,从而在变换器的输入输出之间形成直流隔离.例如,在离线(off-line)应用中(变换器输入连接到交流公用系统),根据监管部门要求, ...

  10. 02-MySQL主要配置文件

    一.二进制日志log-bin 作用:主从复制 二.错误日志 log-err 默认关闭,记录严重的警告和错误信息,每次启动和关闭的详细信息 三.慢查询日志log 默认关闭,记录查询的sql语句,如果开启 ...