题意:
一个城市中有n个大楼,m个避难所,接下来给出n个大楼的坐标和人数,接下来m行给出每个避难所的坐标和容纳量,大楼到避难所的距离定义为曼哈顿距离+1,然后给出n行m列数据,第i行第j列代表从第i个大楼到第j个避难所去的人数,保证此方案合法,然后判断此方案是否所有人到避难所的距离和最小,是的话输出OPTIMAL,否则给出更好的方案,但不一定是最优的;
思路:
如果用最小费用最大流算法直接求解,会超时,此时有个更巧妙的算法,因为题目中已经给出了一套方案,然后就利用给出的方案建立残留网络图,寻找是否存在负圈,存在的话肯定不是最优,找到这个负圈,顺着负圈增广,得到一个更优(不一定最优)的解就行了,题目不要求最优。
所谓消圈定理,就是在某个流 中,如果其对应的残余网络(剩余流量为 0 的边视为不存在)没有负圈,那它一定就是当前流量下的最小费用流。反之亦然。即「 是最小费用流等价于其残余网络中没有负圈」。
建图是关键。建残量网络,每条边只需要一个剩余流量remains和代价cost即可,剩余流量为0意味着残量网络中不存在这条边。remains(i, j)表示 i 到 j 的残量,那么
比如上面这个边,u到v容量是11,流量是5,那么remain(u , v) = 11 - 5 = 6; 而remian(v , u) = 5(cap(v , u) = 0, flow(v , u) = -5)。对于正向弧(i,j),flow(i,j) = remain(j,i)。只要把remains更新好,最后输出flow时转成反向弧输出就好了。
建筑 i 到防空洞 j 的容量可设为INF,输入给出了流量,则remains(i , j) = INF - f, cost = …;
相应反向弧remains(j , i) = f,cost取反;
建立源点s, 设建筑 i 的流出的流量和为tot1[i], 而s 到 i 的容量为B[i].c(建筑i的人数),其残量为B[i].c - tot1[i].。
汇点同理。
邻接表
#include <cstdio>
#include <queue>
#include <vector