鸣谢: 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的更多相关文章

  1. POJ-2175 Evacuation Plan 最小费用流、负环判定

    题意:给定一个最小费用流的模型,根据给定的数据判定是否为最优解,如果不为最优解则给出一个比给定更优的解即可.不需要得出最优解. 解法:由给定的数据能够得出一个残图,且这个图满足了最大流的性质,判定一个 ...

  2. POJ2175 Evacuation Plan

    Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4617   Accepted: 1218   ...

  3. 最小费用流判负环消圈算法(poj2175)

    Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3384   Accepted: 888   ...

  4. POJ2175:Evacuation Plan(消负圈)

    Evacuation Plan Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 5665Accepted: 1481Special J ...

  5. poj2175费用流消圈算法

    题意:      有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否 ...

  6. OJ题目分类

    POJ题目分类 | POJ题目分类 | HDU题目分类 | ZOJ题目分类 | SOJ题目分类 | HOJ题目分类 | FOJ题目分类 | 模拟题: POJ1006 POJ1008 POJ1013 P ...

随机推荐

  1. 复习day12-23

    获取请求中的内容: request.getParameter(); get方式因为在地址栏所以需要转码: String name = new String(req.getparameter().get ...

  2. 通过属性集名称获取属性集id

    Mage::getModel('eav/entity_attribute_set')->load('属性集名称', 'attribute_set_name')->getAttributeS ...

  3. Magento布局layout.xml文件详解

    解析顺序 布局xml文件一般位于app/design/{area}/{package}/{theme}/layout/目录下.Layout文件一般包含block.reference.action三种标 ...

  4. Eclipse:使用findBugs预先检测错误

    FindBugs是用于Java的另一种静态分析工具,它在某些方面与Checkstyle和PMD类似,但是侧重点不同.FindBugs不关心格式或编码标准,对最佳实践也不太感兴趣:事实上,它专注于检查潜 ...

  5. 如何修改 UINavigationController、UINavigationBar 中 navigationItem 左侧 “返回” 按钮的名称

    如果我们从 title 为 “首页” 的页面 A 点击进入一个子页面 B,那么在页面 B 的左上角将显示一个名为 “<首页” 的按钮.假设这个页面 A 叫 “你是我天边最美的云彩”,那在页面 B ...

  6. 扑克k,你知道的人物吗?

    在扑克牌中,黑桃K——大卫王(以色列联合王国第二任国王):红桃K——查里曼大帝(法兰克国王,后加冕为罗马人的皇帝):梅花K——亚历山大大帝(马其顿帝国国王):方块K——凯撒大帝(罗马共和国终生执政官) ...

  7. node.js(三)url处理

    1.parse函数的基础用法 parse函数的作用是解析url,返回一个json格式的数组,请看如下示例: var url = require('url'); url.parse('http://ww ...

  8. JAVA-反射-getGenericSuperclass()

    1 public class Person<T> { 2 3 } 4 5 import java.lang.reflect.ParameterizedType; 6 import java ...

  9. SQL数据库知识二(Day 25)

    又到了总结知识的时候了,今天主要把SQL数据库给简单的学完了,明天开始就要开始学ADO.NET的知识了.好了,话不多说,还是看一下今天都学了哪些内容. 1  字符串类型的知识点 --类型的使用 --截 ...

  10. Linux学习之nl命令

    nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等 ...