poj2175
鸣谢: http://www.cppblog.com/y346491470/articles/152317.html
【题意】:一个城市有n座建筑物,每个建筑物里面有一些人,为了在战争爆发时这些人都可以避难,城市里面建了m座避难所。每座避难所只能容纳有限人数。给出每个建筑物和避难所的坐标(题目要求距离为曼哈顿距离+1)。现在给你一种避难方案,问这种方案是否为最优方案,如果不是,请输出一种比当前更优的方案(不一定最优)。
【题解】:好明显的费用流(距离看成费用),如果此题建费用流模型找最小费用流必定超时,而且题目不需要我们找到最优方案。
定理:一个费用流是最小费用流的充要条件是这个费用流的残量网络没有负费用环。
由这个定理,我们只需判断当前方案是否有负费用圈,没有即意味着当前方案为最优方案。
如果有的话,此时只需沿着负费用圈把各边流量增加1,增流之后残量网络对应的方案肯定是一个更优方案(很容易证明)。
SPFA找负环: 某个点进入队列大于等于nodes次证明存在负环。(nodes一般情况是顶点个数,这道题给图很特殊,取max{n,m}就可以)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = ;
const int maxe = ;
const int maxdist = <<;
const int maxf = <<;
struct edge{
int u,v,c,cost;
edge(int e1=,int e2=,int e3=,int e4=){ u=e1; v=e2; c=e3; cost=e4; }
}e[maxe];
int cnt;
int head[maxn];
int next[maxe];
void add(int u,int v,int c,int w,int f){
e[cnt] = edge(u,v,c-f,w);
next[cnt]=head[u], head[u] = cnt++;
e[cnt] = edge(v,u,f,-w);
next[cnt]=head[v], head[v] = cnt++;
}
int source,sink,nodes;
int spfa(){
queue<int> que;
que.push(sink);
int dist[maxn],inque[maxn],visits[maxn],pre[maxn];
for(int i=;i<=nodes;i++)
dist[i]=maxdist,inque[i]=,visits[i]=,pre[i]=-;
int u,v,neg_loop=;
dist[sink]=;
while(!que.empty()){
u=que.front(); que.pop(); inque[u]=;
visits[u]++;
if(visits[u] > nodes) { //产生了负环
neg_loop=; break;
}
//printf("u = %d, visits[u] = %d\n",u,visits[u]);
for(int i=head[u];i>=;i=next[i])
if(e[i].c && dist[e[i].v] > dist[u]+e[i].cost){
v=e[i].v;
dist[v] = dist[u]+e[i].cost;
if(!inque[v])
que.push(v), inque[v]=;
pre[v]=i;
} }
int visited[maxn]={},i;
if(neg_loop){
int counter=nodes; //负环长肯定不超过顶点数,而抛出负环的点不一定在负环中
while(counter--)
u=e[pre[u]].u;
while(!visited[u]){
i=pre[u],visited[u]++,e[i].c--,e[i^].c++;
//printf("u = %d, i = %d, %d --> %d\n",u,i,e[i].u,e[i].v);
u=e[i].u;
}
}
return neg_loop;
}
void initial(){
cnt = ;
memset(head,-,sizeof(head));
//initial source,sink and nodes;
}
struct pos{
int x,y;
}building[],shelter[];
int getdist(pos &s,pos &t){
int ret=s.x-t.x;
if(ret < ) ret=-ret;
if(s.y > t.y) ret+=s.y-t.y;
else ret+=t.y-s.y;
ret++;
return ret;
}
int bi[],si[],dist[][],plan[][];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m) != EOF){
for(int i=;i<=n;i++)
scanf("%d%d%d",&building[i].x,&building[i].y,&bi[i]);
for(int i=;i<=m;i++)
scanf("%d%d%d",&shelter[i].x,&shelter[i].y,&si[i]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
dist[i][j]=getdist(building[i],shelter[j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&plan[i][j]);
int flag=;
//****************************************//
for(int i=;i<=n;i++) plan[i][]=;
for(int j=;j<=m;j++) plan[][j]=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
plan[i][]+=plan[i][j],plan[][j]+=plan[i][j];
for(int i=;i<=n;i++)
if(plan[i][] != bi[i])
flag=;
for(int j=;j<=m;j++)
if(plan[][j] > si[j])
flag=;
//****************************************//一些额外的判断
initial();
source=,sink=n+m+,nodes=sink+;
for(int i=;i<=n;i++) add(source,i,bi[i],,bi[i]);
for(int j=;j<=m;j++) add(n+j,sink,si[j],,plan[][j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
add(i,j+n,bi[i],dist[i][j],plan[i][j]);
if(!flag)
flag = spfa();
if(!flag) printf("OPTIMAL\n");
else {
printf("SUBOPTIMAL\n");
memset(plan,,sizeof(plan));
for(int u=,v;u<=n;u++)
for(int i=head[u];i>=;i=next[i]){
v=e[i].v;
if(v > n) v -= n;
plan[u][v] += e[i^].c;
}
for(int i=;i<=n;i++){
for(int j=;j<m;j++) printf("%d ",plan[i][j]);
printf("%d\n",plan[i][m]);
}
}
}
return ;
}
poj2175的更多相关文章
- POJ-2175 Evacuation Plan 最小费用流、负环判定
题意:给定一个最小费用流的模型,根据给定的数据判定是否为最优解,如果不为最优解则给出一个比给定更优的解即可.不需要得出最优解. 解法:由给定的数据能够得出一个残图,且这个图满足了最大流的性质,判定一个 ...
- POJ2175 Evacuation Plan
Evacuation Plan Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4617 Accepted: 1218 ...
- 最小费用流判负环消圈算法(poj2175)
Evacuation Plan Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3384 Accepted: 888 ...
- POJ2175:Evacuation Plan(消负圈)
Evacuation Plan Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 5665Accepted: 1481Special J ...
- poj2175费用流消圈算法
题意: 有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否 ...
- OJ题目分类
POJ题目分类 | POJ题目分类 | HDU题目分类 | ZOJ题目分类 | SOJ题目分类 | HOJ题目分类 | FOJ题目分类 | 模拟题: POJ1006 POJ1008 POJ1013 P ...
随机推荐
- POJ 1703 Find them, Catch them (数据结构-并查集)
Find them, Catch them Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 31102 Accepted: ...
- html系列教程--header head iframe img
<head> 标签 用于定义文档的头部,它是所有头部元素的容器.<head> 中的元素可以引用脚本.指示浏览器在哪里找到样式表.提供元信息 head的描述信息包括<bas ...
- Nutch的发展历程
Nutch的创始人是Doug Cutting,他同时也是Lucene.Hadoop和Avro开源项目的创始人 下面是Nutch的发展历程: 月由Doug Cutting发起,托管于Sourceforg ...
- 最大稳定极值区域(MSER)检测
http://blog.csdn.net/zizi7/article/details/50379973 http://www.cnblogs.com/dawnminghuang/p/3779552.h ...
- 常用封装--Date篇--获取格式化的日期对象
虽然日期对象可以使用new Date()来获取,但是对于其格式却必须进行相应的转换,才能成为开发者想要的格式. 这里提供了一个封装的方法,通过结合正则表达式的使用,达到了可以对时间对象进行处理,生成多 ...
- 游戏基础元素——Cocos2d-x学习历程(八)
1.Director:导演 从字面上理解,这是一个"导演"类,Director是控制游戏流程的主要组件.CCDirector的工作确实跟导演非常类似,主要负责以下工作: 游戏呈现方 ...
- css书写顺序和常用命名推荐
写代码的时候有一个好的规范和顺序能够帮你节省很多时间.下文将推荐相关CSS书写顺序和规范的一些方法.这个文档将会整理进前端规范文档中,如果你有更好的意见,不妨留言告知我们. CSS书写顺序 该代码来自 ...
- ie6,ie7,ie8 css bug汇总以及兼容解决方法
1:li边距“无故”增加 任何事情都是有原因的,li边距也不例外. 先描述一下具体状况:有些时候li边距会突然增 加很多,值也不固定(只在IE6/IE7有这种现象),让人摸不着头脑,仔细“研究”发现是 ...
- jquery学习(3)--高级选择器
自己手写的学习笔记.常规选择器: /****************学习--高级选择器(1)****************/---高级选择器:ie7+ 层次选择器: 后代选择器 ul li ...
- 高精度 java的一些题
poj 1001 Exponentiation import java.util.*; import java.math.*; public class Main { public static vo ...