http://poj.org/problem?id=2175

题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给出一个方案,问该方案是否是让所有人到防空洞避难的花费时间最少的方案,如果不是,输出一个最佳方案。

思路:一开始直接用最小费用最大流,超时了。学习了一下消圈算法。

如果不考虑得到最小费用,只需要考虑当前是否最小费用的话,那么是可以用消圈算法来解决的。

结论:当没有负圈的时候,当前的费用是最小的。

因此,构图的时候,根据给出的方案构造出残余网络,然后直接跑一遍SPFA,如果出现负圈,说明当前的答案不是最优的(因为反向边是-cost,可以得到更小的费用,因此是负圈)。

考虑构造新的方案:对于该负圈,记录起路径,然后遍历,因为图存的是正向边的流量,所以如果正向边出现在负圈里,需要加上,代表跑这条边更优,反向边则减去。

学习地址

 #include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
using namespace std;
#define INF 0x3f3f3f3f
#define N 210
typedef long long LL;
struct Edge {
int u, v, nxt, cap, cost;
} edge[N*N];
int head[N], tot, pre[N], dis[N], vis[N], inq[N], x[N], y[N], b[N], p[N], q[N], c[N], mp[N][N], S, T; void Add(int u, int v, int cap, int now, int cost) {
edge[tot] = (Edge) { u, v, head[u], cap - now, cost }; head[u] = tot++;
edge[tot] = (Edge) { v, u, head[v], now, -cost }; head[v] = tot++;
} int cal(int x1, int y1, int x2, int y2) { return abs(x2 - x1) + abs(y2 - y1) + ; } int SPFA(int S, int n) {
queue<int> que;
que.push(S);
memset(dis, INF, sizeof(dis));
memset(vis, , sizeof(vis));
memset(inq, , sizeof(inq));
dis[S] = ; vis[S] = ; pre[S] = S;
while(!que.empty()) {
int u = que.front(); que.pop();
vis[u] = ;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v, cost = edge[i].cost, cap = edge[i].cap;
if(dis[v] > dis[u] + cost && cap > ) {
dis[v] = dis[u] + cost; pre[v] = u;
if(!vis[v]) {
vis[v] = , que.push(v);
if(++inq[v] > n) return v;
}
}
}
}
return ;
} bool inside(int L, int R, int now) { if(L <= now && now <= R) return true; return false; } int main() {
int n, m;
while(~scanf("%d%d", &n, &m)) {
S = , T = n + m + ; int res = , ans;
memset(head, -, sizeof(head)), tot = ;
memset(dis, , sizeof(dis));
for(int i = ; i <= n; i++) scanf("%d%d%d", &x[i], &y[i], &b[i]);
for(int i = ; i <= m; i++) scanf("%d%d%d", &p[i], &q[i], &c[i]);
for(int i = ; i <= n; i++) for(int j = ; j <= m; j++) {
scanf("%d", &mp[i][j]);
int d = cal(x[i], y[i], p[j], q[j]);
Add(i, j + n, INF, mp[i][j], d);
res += d * mp[i][j]; dis[j] += mp[i][j];
}
for(int i = ; i <= n; i++) Add(S, i, b[i], , );
for(int i = ; i <= m; i++) Add(i + n, T, c[i], dis[i], );
ans = SPFA(S, T);
if(!ans) puts("OPTIMAL");
else {
memset(vis, , sizeof(vis));
while(!vis[ans]) { vis[ans] = ; ans = pre[ans]; }
int tmp = ans;
do { // 图存的是正向边的流量,因此如果正向边出现在负圈里,需要加上,代表跑这条边更优,反向边减去
if(inside(, n, pre[tmp]) && inside(n + , n + m, tmp)) mp[pre[tmp]][tmp-n]++;
if(inside(, n, tmp) && inside(n + , n + m, pre[tmp])) mp[tmp][pre[tmp]-n]--;
tmp = pre[tmp];
} while(tmp != ans);
puts("SUBOPTIMAL");
for(int i = ; i <= n; i++) for(int j = ; j <= m; j++)
printf("%d%c", mp[i][j], j == m ? '\n' : ' ');
}
}
return ;
} /*
3 4
-3 3 5
-2 -2 6
2 2 5
-1 1 3
1 1 4
-2 -2 7
0 -1 3
3 1 1 0
0 0 6 0
0 3 0 2
*/

POJ 2175:Evacuation Plan(费用流消圈算法)***的更多相关文章

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

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

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

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

  3. poj2175费用流消圈算法

    题意:      有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否 ...

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

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

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

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

  6. poj 2175 费用流消圈

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

  7. POJ - 2175 Evacuation Plan (最小费用流消圈)

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

  8. POJ 2175 Evacuation Plan

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

  9. Codeforces Gym 100002 E "Evacuation Plan" 费用流

    "Evacuation Plan" Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10 ...

随机推荐

  1. Qt调用PolarSSL库(一个)

    最近一直在学习SSL相关知识,也明白了理论相关知识,主要SSL基本概念和连接建立.主要依据PolarSSL开源库学习.学习完了之后就希望能给有所运用,就想用Qt写一个简单的程序,添加对SSL相关概念的 ...

  2. 【从翻译mos文章】在oracle db 11gR2版本号被启用 Oracle NUMA 支持

    在oracle db 11gR2版本号被启用 Oracle NUMA 支持 参考原始: Enable Oracle NUMA support with Oracle Server Version 11 ...

  3. Linking different libraries for Debug and Release builds in Cmake on windows?

    问题叙述性说明: So I've got a library I'm compiling and I need to link different third party things in depe ...

  4. eXtremeDB -- the shared memory 80error

    The customers got the shared memory 80error on AIX environment; utility truss is used to track the d ...

  5. WPF 使用Propereties:Resources.resx里面的资源

    <Window x:Class="Wpf180706.Window7"        xmlns="http://schemas.microsoft.com/win ...

  6. C#使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值)

    原文:C#使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值) 1.问题的提出: 电池生产中,遇到一批电池的测量结果数据: 电压值 电池个数 电压值 电池个数 电压值 电池个数 电 ...

  7. Django 创建超级管理员失败

    django.db.utils.DataError: (1406, "Data too long for column 'gender' at row 1") 解决方案 在执行mi ...

  8. ubuntu 16.04 android studio 开发环境搭建

    安装步骤: 1. 安装 Java developer kit 2.安装 Android developer kit 3.安装 Android studio 4.真机调试 第一次用Linux,命令基本不 ...

  9. nginx 简单应用

    从源代码编译 Nginx 把源码解压缩之后,在终端里运行如下命令: $ ./configure $ make $ sudo make install 默认情况下,Nginx 会被安装在 /usr/lo ...

  10. Go语言v1.8正式发布,有显著的性能提升和变化(go适合服务器编程、网络编程)

    前言 Go语言现在在服务端的网络编程领域越来越火,尤其像IM即时通讯应用这种富网络应用且对服务端网络性能要求极高的场景,很高兴看到Golang发布了1.8正式版,希望在多核架构横行的时代多一些这种顺应 ...