题意:
     有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感觉下),具体看代码。


#include<queue>
#include<stdio.h>
#include<string.h>#define N_node 205
#define N_edge 30000
#define INF 100000000using namespace std;typedef struct
{int from ,to ,cost ,flow ,next;
}STAR;typedef struct
{int a ,b ,c;
}NODE;STAR E[N_edge];
int list[N_node] ,tot;
int C[N_node];//入队次数
int mer[N_node];//记录路径
int s_x[N_node] ,mark[N_node];
int now[N_node][N_node];
NODE A[N_node] ,B[N_node];void add(int a ,int b ,int c ,int d)
{E[++tot].from = a;E[tot].to = b;E[tot].cost = c;E[tot].flow = d;E[tot].next = list[a];list[a] = tot;
}int abss(int x)
{return x > 0 ? x : -x;
}bool Spfa(int s ,int n)
{for(int i = 0 ;i <= n ;i ++)s_x[i] = INF;memset(mark ,0 ,sizeof(mark));memset(C ,0 ,sizeof(C));queue<int>q; q.push(s);mark[s] = C[s] = 1 ,s_x[s] = 0;int xin ,tou;memset(mer ,255 ,sizeof(mer));while(!q.empty()){tou = q.front();q.pop();mark[tou] = 0;for(int k = list[tou] ;k ;k = E[k].next){xin = E[k].to;if(s_x[xin] > s_x[tou] + E[k].cost && E[k].flow){s_x[xin] = s_x[tou] + E[k].cost;mer[xin] = k;if(!mark[xin]){mark[xin] = 1;q.push(xin);if(++C[xin] > n) return xin;}}}}return 0;
}int main ()
{int n ,m ,i ,j;int st[N_node];while(~scanf("%d %d" ,&n ,&m)){for(i = 1 ;i <= n ;i++)scanf("%d %d %d" ,&A[i].a ,&A[i].b ,&A[i].c);for(i = 1 ;i <= m ;i ++)scanf("%d %d %d" ,&B[i].a ,&B[i].b ,&B[i].c);memset(st ,0 ,sizeof(st));for(i = 1 ;i <= n ;i ++)for(j = 1 ;j <= m ;j ++){scanf("%d" ,&now[i][j]);st[j] += now[i][j];}memset(list ,0 ,sizeof(list));tot = 1;int ss = 0 ,tt = n + m + 1;for(i = 1 ;i <= n ;i ++)add(ss ,i ,0 ,0),add(i ,ss ,0 ,A[i].c);for(i = 1 ;i <= m ;i ++)add(i + n ,tt ,0 ,B[i].c - st[i]) ,add(tt ,i + n ,0 ,st[i]);for(i = 1 ;i <= n ;i ++)for(j = 1 ;j <= m ;j ++){add(i ,j + n ,abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1 ,INF - now[i][j]);add(j + n ,i ,-(abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1) ,now[i][j]);}int x = Spfa(tt ,tt);if(!x){printf("OPTIMAL\n");continue;}printf("SUBOPTIMAL\n");memset(mark ,0 ,sizeof(mark));i = mer[x];while(1)//找到一个肯定在环上的点{x = E[i].to;if(mark[x]) break;mark[x] = 1;i = mer[E[i].from];}memset(mark ,0 ,sizeof(mark));for(i = mer[x] ;i + 1 ;i = mer[E[i].from]){int a = E[i].from ,b = E[i].to;if(a >= 1 && a <= n && b >= n + 1 && b <= n + m)now[a][b-n] ++;if(a >= n + 1 && a <= n + m && b >= 1 && b <= n)now[b][a-n] --;if(mark[a] && mark[b]) break;mark[a] = mark[b] = 1;}for(i = 1 ;i <= n ;i ++)for(j = 1 ;j <= m ;j ++)if(j == m) printf("%d\n" ,now[i][j]);else printf("%d " ,now[i][j]);}return 0;}

poj2175费用流消圈算法相关推荐

  1. 消圈算法c语言,【图论】Floyd消圈算法

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

  2. POJ - 2175 Evacuation Plan(最小费用最大流+消圈定理)

    题目链接:点击查看 题目大意:给出n个建筑物和m个避难所,每个建筑物中的人需要到避难所中去避难,规定花费是建筑物和避难所的曼哈顿距离+1,现在给出一种路线方案,问这个方案是不是最优的,如果不是,输出比 ...

  3. 【2018山东省赛 - A】Anagram(贪心,费用流,KM算法)

    题干: Problem Description Orz has two strings of the same length: A and B. Now she wants to transform ...

  4. 一种更高效的费用流算法——zkw费用流

    orz原创者zkw%%% 送上zkw神犇的blog原址:传送门 费用流建立在网络最大流的基础上,一张图中最大流有且仅有一个,但是最大流条数往往不止一条,这时候对于我们来说,可能要找出这些最大流中最小( ...

  5. BZOJ3291Alice与能源计划——匈牙利算法+模拟费用流

    题目描述 在梦境中,Alice来到了火星.不知为何,转眼间Alice被任命为火星能源部长,并立刻面临着一个严峻的考验.为 了方便,我们可以将火星抽象成平面,并建立平面直角坐标系.火星上一共有N个居民点 ...

  6. 一篇网络流 基本模型超全总结(最大流 费用流 多源汇最大流 上下界可行流) 思路+代码模板

    文章目录 一.网络流与最大流 二.网络流三个基本性质 三.重要定义定理 四.最大流算法 <Ⅰ> Edmonds-Karp算法(EK算法) 1.EK算法 2.算法思想: 3.代码模板 4.模 ...

  7. 餐巾计划问题 线性规划与网络流24题之10 费用流

    相关知识:最小费用(最大)流 问题描述: 一个餐厅在相继的N 天里, 每天需用的餐巾数不尽相同. 假设第i天需要ri块餐巾(i=1, 2,-,N).餐厅可以购买新的餐巾,每块餐巾的费用为p分:或者把旧 ...

  8. BZOJ 1061费用流

    思路: 我们可以列出几个不等式 用y0带进去变成等式 下-上 可以消好多东西 我们发现 等式左边的加起来=0 可以把每个方程看成一个点 正->负 连边 跑费用流即可 //By SiriusRen ...

  9. 初识费用流 模板(spfa+slf优化) 餐巾计划问题

    今天学习了最小费用最大流,是网络流算法之一.可以对于一个每条边有一个容量和一个费用(即每单位流的消耗)的图指定一个源点和汇点,求在从源点到汇点的流量最大的前提下的最小费用. 这里讲一种最基础也是最好掌 ...

最新文章

  1. python类和对象介绍_python中的类,对象,方法,属性等介绍
  2. java 发送tcp_Java TCP发送与接收
  3. javascript php 性能,浅谈页面装载js及性能分析方法_javascript技巧
  4. org.activiti.engine.ActivitiException: src-resolve: Cannot resolve the name 'extension' to a(n) 'ele
  5. 多线程socket 端口扫描程序,实现了,但是速度不行,求指点。
  6. MySQL数据库和Oracle数据库的区别
  7. python sql注入脚本_python辅助sql手工注入猜解数据库案例分析
  8. 实现带有拉普拉斯修正的朴素贝叶斯_数据科学 | 算法工程师必备的机器学习贝叶斯分类器...
  9. 【房价预测】基于matlab遗传算法优化BP神经网络房价预测【含Matlab源码 592期】
  10. MacBook上有哪些相见恨晚的神器
  11. 667. 优美的排列 II
  12. 统计学之离散指标(全距、内距、异众比率、平均差与标准差)
  13. 基于Java毕业设计校园外卖零食商城系统源码+系统+mysql+lw文档+部署软件
  14. DevCloud注册和登录
  15. P2900 [USACO08MAR]土地征用Land Acquisition(斜率优化)
  16. [UOJ198]时空旅行
  17. failed to push some refs to 'git@xxx.xxx.xxx.xxx:finger-shoot/shoot-admin.git'
  18. 安装Linux 乌班图 Ubuntu 系统
  19. 如何理解接口隔离原则?
  20. android 模拟器输入中文

热门文章

  1. 《OpenGL ES 3.x游戏开发(下卷)》一1.2 顶点数组对象
  2. DJANGO用户名认证一例
  3. Java EE WEB工程师培训-JDBC+Servlet+JSP整合开发之06.JDBC PreparedStatement
  4. Winpcap 中sockaddr_storage问题收藏
  5. python常用模块之shelve模块
  6. 20165237 2017-2018-2 《Java程序设计》第5周学习总结
  7. Mysql优化原则_小表驱动大表IN和EXISTS的合理利用
  8. 【学习记录】无法找到“Procedural Foliage Spawner”
  9. 转:马云语录之公司请你来干嘛
  10. freebsd 域名服务器