题意:有N栋楼,每栋楼有\(val_i\)个人要避难,现在有M个避难所,每个避难所的容量为\(cap_i\),每个人从楼i到避难所j的话费是两者的曼哈顿距离.现在给出解决方案,问这个解决方案是否是花费最小的,若不是,则给出比这个更优的解.

分析:若只是要我们求一个最优解的话就用费用流做.现在要求判断是否最优,那么就是当前这张图中是否最短路还能被更新.

首先需要根据给定的解决方案重现这个状态下的残余网,其实只需要加入必要的弧即可:对与任意的楼与避难所(i,j),建边,费用为其距离;若i->j有流量,则反向弧也需要加入,费用为-|距离|.

对于源点s和汇点t.其实没必要加入源点出发的边,只考虑到达t的边.这部分的弧显然费用不用考虑,为0即可.因为汇点是与避难所相连,统计每个避难所的入流,若入流不为0,需要加入反向弧,若已经满流,则说明已经不可增广,则不用加入该弧.

最后从汇点出发跑一遍spfa,若存在负环,则只要在任意一个负环中走一遍即可减少费用.在spfa的过程中记录每个点的前驱,这样绕着环走一遍,注意判断边(i,j)的意义,可能是楼i到避难所j多去一个人,也可能是避难所j往i回退一个人.

  1. #include<iostream>
  2. #include<cstring>
  3. #include<stdio.h>
  4. #include<algorithm>
  5. #include<set>
  6. #include<map>
  7. #include<vector>
  8. #include<stack>
  9. #include<queue>
  10. using namespace std;
  11. const int MAXN = 1005;
  12. const int MAXM = 100000;
  13. const int INF = 0x3f3f3f3f;
  14. struct Edge{
  15. int to, next, cap, flow, cost;
  16. } edge[MAXM];
  17. int head[MAXN], tot;
  18. int pre[MAXN], dis[MAXN];
  19. bool vis[MAXN];
  20. int cnt[MAXN];
  21. int N;
  22. void init(int n)
  23. {
  24. N = n;
  25. tot = 0;
  26. memset(head, -1, sizeof(head));
  27. }
  28. void AddEdge(int u, int v,int cost)
  29. {
  30. edge[tot] = (Edge){v,head[u],0,0,cost};
  31. head[u] = tot++;
  32. //edge[tot] = (Edge){u,head[v],0,0,-cost};
  33. //head[v] = tot++;
  34. }
  35. int spfa(int s){
  36. queue<int> q;
  37. for (int i = 0; i < N; i++){
  38. dis[i] = INF;
  39. vis[i] = false;
  40. pre[i] = -1;
  41. cnt[i] = 0;
  42. }
  43. dis[s] = 0;
  44. vis[s] = true;
  45. q.push(s);
  46. while (!q.empty()){
  47. int u = q.front();
  48. q.pop();
  49. vis[u] = false;
  50. for (int i = head[u]; i != -1; i = edge[i].next){
  51. int v = edge[i].to;
  52. if (dis[v] > dis[u] + edge[i].cost){
  53. dis[v] = dis[u] + edge[i].cost;
  54. pre[v] = u; //记录前驱
  55. if (!vis[v]){
  56. vis[v] = true;
  57. q.push(v);
  58. if(++cnt[v]>N) return v; //有负环,能减小花费
  59. }
  60. }
  61. }
  62. }
  63. return -1;
  64. }
  65. struct Point{
  66. int x,y,val;
  67. }p[MAXN],vz[MAXN];
  68. int dist(const Point &a, const Point &b){
  69. return abs(a.x-b.x) + abs(a.y-b.y) ;
  70. }
  71. int G[105][105];
  72. int num[105];
  73. int main()
  74. {
  75. #ifndef ONLINE_JUDGE
  76. freopen("in.txt","r",stdin);
  77. freopen("out.txt","w",stdout);
  78. #endif
  79. int N,M;
  80. while(scanf("%d %d",&N, &M)==2){
  81. init(N+M+2);
  82. int s=0,t=N+M+1;
  83. for(int i=1;i<=N;++i){
  84. scanf("%d %d %d",&p[i].x, &p[i].y, &p[i].val);
  85. }
  86. for(int i=1;i<=M;++i){
  87. scanf("%d %d %d",&vz[i].x,&vz[i].y, &vz[i].val);
  88. }
  89. memset(num,0,sizeof(num));
  90. for(int i=1;i<=N;++i){
  91. for(int j=1;j<=M;++j){
  92. scanf("%d",&G[i][j]);
  93. int d = dist(p[i],vz[j]);
  94. AddEdge(i,j+N,d);
  95. num[j] += G[i][j];
  96. if(G[i][j]) AddEdge(j+N,i,-d); //有流量说明有反向边
  97. }
  98. }
  99. for(int i=1;i<=M;++i){ //此处s表示实际网络里的汇点
  100. if(num[i]){ //有流量则有反向边
  101. AddEdge(s,i+N,0);
  102. if(num[i]<vz[i].val){ //没漫流说明还有继续推进的空间
  103. AddEdge(i+N,s,0);
  104. }
  105. }
  106. }
  107. int u = spfa(s);
  108. if(u==-1){
  109. printf("OPTIMAL\n");
  110. }
  111. else{
  112. printf("SUBOPTIMAL\n");
  113. memset(vis,0,sizeof(vis));
  114. int v = u;
  115. while(!vis[pre[v]]){
  116. vis[v] = 1;
  117. v = pre[v];
  118. }
  119. int cur = v;
  120. do{
  121. int fa = pre[cur];
  122. if(fa<=N && cur>N)
  123. G[fa][cur-N]++; //走这条边代表楼i->避难所j多一个人能更优
  124. else if(fa>N && cur<=N)
  125. G[cur][fa-N]--; //同理
  126. cur = fa;
  127. }while(cur!=v);
  128. for(int i=1;i<=N;++i){
  129. for(int j=1;j<=M;++j){
  130. printf("%d%c",G[i][j],j==M?'\n':' ');
  131. }
  132. }
  133. }
  134. }
  135. return 0;
  136. }

POJ - 2175 Evacuation Plan (最小费用流消圈)的更多相关文章

  1. poj 2175 Evacuation Plan 最小费用流判定,消圈算法

    题目链接 题意:一个城市有n座行政楼和m座避难所,现发生核战,要求将避难所中的人员全部安置到避难所中,每个人转移的费用为两座楼之间的曼哈顿距离+1,题目给了一种方案,问是否为最优方案,即是否全部的人员 ...

  2. POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)

    http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submi ...

  3. POJ 2175 Evacuation Plan

    Evacuation Plan Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Origina ...

  4. POJ.2175.Evacuation Plan(消圈)

    POJ \(Description\) \(n\)个建筑物,每个建筑物里有\(a_i\)个人:\(m\)个避难所,每个避难所可以容纳\(b_i\)个人. 给出每个建筑物及避难所的坐标,任意两点间的距离 ...

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

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

  6. POJ 2175 spfa费用流消圈

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

  7. POJ2175:Evacuation Plan(消负圈)

    Evacuation Plan Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 5665Accepted: 1481Special J ...

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

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

  9. POJ-2175 Evacuation Plan 最小费用流、负环判定

    题意:给定一个最小费用流的模型,根据给定的数据判定是否为最优解,如果不为最优解则给出一个比给定更优的解即可.不需要得出最优解. 解法:由给定的数据能够得出一个残图,且这个图满足了最大流的性质,判定一个 ...

随机推荐

  1. soundpool播放声音

    一般大家使用的是MediaPlayer来播放音频,它的创建和销毁都是非常消耗资源的,如果我们的需求是播放一些短促而且频繁播放的音频的话MediaPlayer就有些不合适了,我们来讲讲SoundPool ...

  2. Spring中bean的作用范围

    singleton作用域: Spring的scope的默认值是singleton Spring 只会为每一个bean创建一个实例,并保持bean的引用. <bean id="bean的 ...

  3. 【BZOJ4873】[Shoi2017]寿司餐厅 最大权闭合图

    [BZOJ4873][Shoi2017]寿司餐厅 Description Kiana最近喜欢到一家非常美味的寿司餐厅用餐.每天晚上,这家餐厅都会按顺序提供n种寿司,第i种寿司有一个代号ai和美味度di ...

  4. SharePoint PerformancePoint开发实例

    前言 由于工作的原因,有一段时间没有发新的随笔了,最近使用了SharePoint PerformancePoint做了一些报表,与大家分享经验. 本文完全原创,转载请说明出处,希望对大家有用. 阅读目 ...

  5. content: "\e600"

    w图标生成原理. <style> @font-face { font-family: iconfont-sm; src: url(//at.alicdn.com/t/font_143340 ...

  6. python基础-第十一篇-11.1JavaScript基础

    JavaScript是一门解释型编程语言,主要是增强html页面的动态效果 JavaScript是有三部分组成:ECMAScript.BOM.DOM 单行注释//   多行/*   */(必须是scr ...

  7. Fibonacci----poj3070(矩阵快速幂, 模板)

    题目链接:http://poj.org/problem?id=3070 . 就是斐波那契的另一种表示方法是矩阵的幂: 所以是矩阵快速幂:矩阵快速幂学习 #include <cstdio> ...

  8. 病毒侵袭持续中---hdu3065(AC自动机模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3065 模板题,没什么好说的... #include<stdio.h> #include&l ...

  9. python基础知识体系

    一.编程风格.语法要求.变量格式.基本数据类型.运算.流程控制.用户交互 二.字符串.列表.元组.字典.迭代器和生成器 三.函数.内置函数.文件操作.异常处理.模块.常用模块.lambda.yield ...

  10. virtIO前后端notify机制详解

    2016-11-15 本来这是在前端驱动后期分析的,但是这部分内容比较多,且分析了后端notify前端的机制,所以还是单独拿出一节分析比较好! 还是拿网络驱动部分做案例,网络驱动部分有两个队列,(忽略 ...