POJ.2175.Evacuation Plan(消圈)
\(Description\)
\(n\)个建筑物,每个建筑物里有\(a_i\)个人;\(m\)个避难所,每个避难所可以容纳\(b_i\)个人。
给出每个建筑物及避难所的坐标,任意两点间的距离为它们的曼哈顿距离\(+1\)。
现在给出一个分配方案(\(g[i][j]\)表示第\(i\)个建筑物去第\(j\)个避难所的人数),问是否存在所有人移动的距离之和比当前更小的方案。如果存在,输出任意一组更小的方案。
\(n,m\leq100\)
\(Solution\)
直接跑费用流会T,但是也没必要。
如果残量网络存在负环(只走有流量的边),那么沿该负环继续增广,可以得到一组更优的解。否则就是当前流量下的最小费用流。
所以建出残量网络,找出负环来,在负环上走一遍就行了。
\(S\to i\)的每条边的流量肯定是流满的,所以不需要建(\(i'\to T\)的就不一定了)。
复杂度\(O(nm)\)。(\(m\)是边数)
//688K 329MS
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=205,M=(105*105+N)*2,INF=0x3f3f3f3f;
int Enum,H[N],nxt[M],to[M],cost[M],dis[N],pre[N],g[105][105];
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
inline void AE(int u,int v,int w,int c)
{
if(w) to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, cost[Enum]=c;
}
int SPFA(const int n)
{
static int tm[N];
static bool inq[N];
std::queue<int> q;
memset(dis,0x3f,n+1<<2);
dis[n]=0, q.push(n), tm[n]=1;
while(!q.empty())
{
int x=q.front(); q.pop();
inq[x]=0;
for(int i=H[x],v; i; i=nxt[i])
if(dis[to[i]]>dis[x]+cost[i])
{
dis[v=to[i]]=dis[x]+cost[i], pre[v]=x;
if(!inq[v])
{
if(++tm[v]>=n) return v;
q.push(v), inq[v]=1;
}
}
}
return -1;
}
void FindCircle(int x,const int n)
{
static bool vis[N];
while(!vis[x]) vis[x]=1, x=pre[x];//p不一定在环上(但是能回到环),应该先找出来啊。。
int tmp=x;
do
{
int v=pre[x];//v->x
if(x<=n && v>n) --g[x][v-n];
else if(x>n && v<=n) ++g[v][x-n];
x=v;
}while(x!=tmp);
}
int main()
{
static int a[N],b[N],c[N],d[N],cap[N],use[N];
const int n=read(),m=read(),T=n+m+1;
for(int i=1; i<=n; ++i) a[i]=read(),b[i]=read(),read();
for(int i=1; i<=m; ++i) c[i]=read(),d[i]=read(),cap[i]=read();
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j)
{
use[j]+=g[i][j]=read();
int cost=std::abs(a[i]-c[j])+std::abs(b[i]-d[j])+1;
AE(i,j+n,INF-g[i][j],cost), AE(j+n,i,g[i][j],-cost);//negative!
}
for(int i=1; i<=m; ++i) AE(i+n,T,cap[i]-use[i],0), AE(T,i+n,use[i],0);
int p=SPFA(T);
if(p==-1) puts("OPTIMAL");
else
{
FindCircle(p,n), puts("SUBOPTIMAL");
for(int i=1; i<=n; ++i,putchar('\n'))
for(int j=1; j<=m; ++j) printf("%d ",g[i][j]);
}
return 0;
}
POJ.2175.Evacuation Plan(消圈)的更多相关文章
- POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)
http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS Memory Limit: 65536K Total Submi ...
- POJ 2175 Evacuation Plan
Evacuation Plan Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Origina ...
- poj 2175 Evacuation Plan 最小费用流判定,消圈算法
题目链接 题意:一个城市有n座行政楼和m座避难所,现发生核战,要求将避难所中的人员全部安置到避难所中,每个人转移的费用为两座楼之间的曼哈顿距离+1,题目给了一种方案,问是否为最优方案,即是否全部的人员 ...
- POJ - 2175 Evacuation Plan (最小费用流消圈)
题意:有N栋楼,每栋楼有\(val_i\)个人要避难,现在有M个避难所,每个避难所的容量为\(cap_i\),每个人从楼i到避难所j的话费是两者的曼哈顿距离.现在给出解决方案,问这个解决方案是否是花费 ...
- POJ 2175 Evacuation Plan 费用流 负圈定理
题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在 ...
- poj 2175 费用流消圈
题意抽象出来就是给了一个费用流的残存网络,判断该方案是不是最优方案,如果不是,还要求给出一个更优方案. 在给定残存网络上检查是否存在负环即可判断是否最优. 沿负环增广一轮即可得到更优方案. 考虑到制作 ...
- POJ 2157 Evacuation Plan [最小费用最大流][消圈算法]
---恢复内容开始--- 题意略. 这题在poj直接求最小费用会超时,但是题意也没说要求最优解. 根据线圈定理,如果一个跑完最费用流的残余网络中存在负权环,那么顺着这个负权环跑流量为1那么会得到更小的 ...
- POJ 2175:Evacuation Plan(费用流消圈算法)***
http://poj.org/problem?id=2175 题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给 ...
- POJ2175:Evacuation Plan(消负圈)
Evacuation Plan Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 5665Accepted: 1481Special J ...
随机推荐
- Eclipse搭建.C#和..NET Core环境
1.在上一篇博客中我介绍了如何使用Eclipse搭建C++.C开发环境,顺带把搭建 .NET Core 和C#也做个介绍.配置任何环境关键是找到要开发语言的编辑器和SDK.eclipse是java开发 ...
- JMeter 如何把上一个请求的结果作为下一个请求的参数 —— 使用正则提取器
有这样一个压力测试环境,有一个上传页面,上传成功之后服务器会返回一些上传信息(比如文件的 id 或者保存路径之类的信息),然后压力机会继续下一个请求,比如调整 id 为 xx 的文件的一些信息等等.问 ...
- 步步为营103-ZTree 二级联动
1:添加引用 <%--流程类别多选--引用js和css文件--开始--%> <link rel="stylesheet" href="../css/zT ...
- webpack学习笔记--整体配置结构
之前的章节分别讲述了每个配置项的具体含义,但没有描述它们所处的位置和数据结构,下面通过一份代码来描述清楚: const path = require('path'); module.exports = ...
- 剑指offer错题记录
错误重点: 1. 传递vector参数时,如果调用函数改变了vector的内容,一定一定要&,传引用保持一致 旋转数组的最小数字:有重复数字情况,二分查找照样搞.情况考虑要周全,当a[mid] ...
- rxjs简单入门
rxjs全名Reactive Extensions for JavaScript,Javascript的响应式扩展, 响应式的思路是把随时间不断变化的数据.状态.事件等等转成可被观察的序列(Obser ...
- memcached 配置
Memcached是一款开源.高性能.分布式内存对象缓存系统,可应用各种需要缓存的场景,其主要目的是通过降低对Database的访问来加速web应用程序.它是一个基于内存的“键值对”存储,用于存储数据 ...
- js+jquery手写弹出提示框
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- PHP中使用CURL实现GET和POST请求(转载)
CURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP.FTP.TELNET等.最爽的是,PHP也支持 CURL 库.使用PHP的CURL 库可以简单和有效地去抓网页.你只 ...
- fillder--信息面板显示请求耗时列
class Handlers--------->Ctrl+R,找到该方法,加上以下方法即可 { // 显示每行请求的发起时间:时分秒毫秒 public static BindUIColumn(& ...