POJ 2175:Evacuation Plan(费用流消圈算法)***
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(费用流消圈算法)***的更多相关文章
- POJ 2175 Evacuation Plan 费用流 负圈定理
题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在 ...
- POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)
http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS Memory Limit: 65536K Total Submi ...
- poj2175费用流消圈算法
题意: 有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否 ...
- POJ 2157 Evacuation Plan [最小费用最大流][消圈算法]
---恢复内容开始--- 题意略. 这题在poj直接求最小费用会超时,但是题意也没说要求最优解. 根据线圈定理,如果一个跑完最费用流的残余网络中存在负权环,那么顺着这个负权环跑流量为1那么会得到更小的 ...
- POJ.2175.Evacuation Plan(消圈)
POJ \(Description\) \(n\)个建筑物,每个建筑物里有\(a_i\)个人:\(m\)个避难所,每个避难所可以容纳\(b_i\)个人. 给出每个建筑物及避难所的坐标,任意两点间的距离 ...
- poj 2175 费用流消圈
题意抽象出来就是给了一个费用流的残存网络,判断该方案是不是最优方案,如果不是,还要求给出一个更优方案. 在给定残存网络上检查是否存在负环即可判断是否最优. 沿负环增广一轮即可得到更优方案. 考虑到制作 ...
- POJ - 2175 Evacuation Plan (最小费用流消圈)
题意:有N栋楼,每栋楼有\(val_i\)个人要避难,现在有M个避难所,每个避难所的容量为\(cap_i\),每个人从楼i到避难所j的话费是两者的曼哈顿距离.现在给出解决方案,问这个解决方案是否是花费 ...
- POJ 2175 Evacuation Plan
Evacuation Plan Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Origina ...
- Codeforces Gym 100002 E "Evacuation Plan" 费用流
"Evacuation Plan" Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10 ...
随机推荐
- Entity framework 更改模型,新增表
在Package Manager Console 中运行命令Enable-Migrations 再次运行可以更新 抄袭 在实体类中增加一个属性以后,执行 Update-Database 命令 ,可以更 ...
- Emgu-WPF 激光雷达研究-移动物体检测
原文:Emgu-WPF 激光雷达研究-移动物体检测 接上篇: https://blog.csdn.net/u013224722/article/details/80738619 先pose出效果图,下 ...
- zend-form笔记
Zend-Form组件包含以下几个对象: 1.Elements:包含了name和attributes, 2.Fieldsets:继承自elements,但允许包含其他fieldset和elements ...
- 生成wsdl代理c#代码
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\wsdl.exe /l:CS /out:d:\ws ...
- SQLServer 使用sp_repldone标识所有未分发的事务为已分发
原文:SQLServer 使用sp_repldone标识所有未分发的事务为已分发 对于发布数据库的数据大量操作时,会使日志扫描并读取太多,会导致分发堵塞很久.也有一些解决方法,参考 <SqlSe ...
- ArcGIS for Desktop入门教程_第八章_Desktop学习资源 - ArcGIS知乎-新一代ArcGIS问答社区
原文:ArcGIS for Desktop入门教程_第八章_Desktop学习资源 - ArcGIS知乎-新一代ArcGIS问答社区 1 学习资源 用户在学习和应用过程中,可以参考的资源如下: 1. ...
- MASMPlus汇编之简单窗体
.386 .model flat,stdcall option casemap:none ;include 定义 include windows.inc include gdi32.inc i ...
- asp.net 调用带证书的webservice解决办法
最近在朋友弄一个调整省政府政务工作流的程序.. 需要把当前的信息推送到政务网上,采用的是带证书的https webservice.. 下面说一下实现过程 第一步,引用webservice地址,删除we ...
- iostat命令浅析
报告中央处理器(CPU)统计信息.整个系统.适配器.TTY 设备.磁盘 CD-ROM.磁带和文件系统的异步输入/输出(AIO)与输入/输出统计信息,iostat也有一个弱点,就是它不能对某个进程进行深 ...
- -bash: /root/java/jdk/bin/java: cannot execute binary file
错误 -bash: /root/java/jdk/bin/java: cannot execute binary file 错误原因 安装的Linux的版本是32位的,下载的软件是64位,版本不兼容, ...