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. mysql重置root密码,并设置可远程访问

    linux系统: mysqld_safe --skip-grant-tables & mysql -u root use mysql UPDATE user SET host = '%' wh ...

  2. 关于idea maven工程创建struts2入门配置及案例

    1.在maven工程下添加需要导入的jar包节点 <dependencies> <dependency> <groupId>org.apache.struts< ...

  3. 修改Hosts不生效的一个场景-web 专题

    准备工作 1.在 QQ互联 申请成为开发者,并创建应用,得到APP ID 和 APP Key.2.了解QQ登录时的 网站应用接入流程.(必须看完看懂) 为了方便各位测试,直接把我自己申请的贡献出来:A ...

  4. JAVASCRIPT高程笔记-------第 七章 函数表达式

    7.1递归 经典递归例子 function factorial(num){ if(num <= 1){ return 1; }else{ return num * factorial(num - ...

  5. Wpf发送接收 win32消息

    #region WPF发送和接收win32消息 public const int WM_GETTEXT = 0x0D; public const int WM_SETTEXT = 0x0C; publ ...

  6. Rails 最佳实践

    在你业务简单的时候,让你简简单单用 ActiveRecord 模型. 复杂的时候,你可以用官方推荐的 Concerns. 更复杂的时候,可以通过 gem 和 API 来拆分. 极端复杂的时候,由于 R ...

  7. 浅谈.NET(C#)与Windows用户账户信息的获取

    原文:浅谈.NET(C#)与Windows用户账户信息的获取 目录 1. 用户账户名称 - 使用Environment类 2. 用户账户信息 - 使用WindowsIdentity和IdentityR ...

  8. Oracle配置OneMap中的sql数据库问题及解决方案

    报错ORA-00900:无效SQL语句,点确定后报错:ORA--00942:表或视图不存在 分析:prompt在Oracle中是打印功能,如果要在PLsql中执行带有prompt的sql文件就会报上面 ...

  9. jdbc连接oracle数据库字符串

    jdbc连接oracle数据库有两种方式: 连接数据库SID 连接数据库service_name 当连接SID时,字符串如下: url::orcl1" password="xxxx ...

  10. 广义线性模型(Generalized Linear Model)

    广义线性模型(Generalized Linear Model) http://www.cnblogs.com/sumai 1.指数分布族 我们在建模的时候,关心的目标变量Y可能服从很多种分布.像线性 ...