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. XF内容视图和框架

    <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http:/ ...

  2. 反编译 war 包成传统项目的方法

    需求 项目老大让外包做了官网,不甚满意,想自己搞搞,遂叫我反编译他们发过来的 war 包. 方法 第一步:解压 war 包其实就是 zip 压缩包,用 zip 解压. 第二步:反编译 查看 war 包 ...

  3. 【msdn wpf forum翻译】获取当前窗口焦点所在的元素

    原文:[msdn wpf forum翻译]获取当前窗口焦点所在的元素 原文地址: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6b ...

  4. 【C#】获取任意文件的缩略图

    原文:[C#]获取任意文件的缩略图 因为用shell取缩略图时,对于损坏的文件,读出来的图有黑边,所以就诞生了以下方法,不过这个效率要比用shell取的低3-4倍. 1.添加类WindowsThumb ...

  5. Android adb shell 无法启动:insufficient permissions for device

    解决办法1:lsusb查看vendorId号,然后在/etc/udev/rules.d/目录下增加(或修改)51-android.rules文件.增加一条记录:SUBSYSTEM=="usb ...

  6. Ubuntu设置MySQL允许远程访问

    1.注释bind-address = 127.0.0.1. 代码如下: > sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf 将bind-address = ...

  7. no identifier specified for entity错误

    未给entity类添加主键造成. 之前出现这个错误是因为忘记给id添加@Id标签.

  8. 改善C#程序的建议6:在线程同步中使用信号量

    原文:改善C#程序的建议6:在线程同步中使用信号量 所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两 ...

  9. Android零基础入门第66节:RecyclerView点击事件处理

    前面两期学习了RecyclerView的简单使用,并为其item添加了分割线.在实际运用中,无论是List还是Grid效果,基本都会伴随着一些点击操作,那么本期就来一起学习RecyclerView的点 ...

  10. webform的图片防盗链

    最近用到域的问题,不是同一主机的请求将不允许请求此页面. 这其实和图片防盗链的本质是一样的. 通过两个属性:由于当时用的aspx视图引擎,所以需要通过HttpContext.Current才能拿到ht ...