鸣谢: 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. sql server操作2:查询数据库语句大全【转】

    注:以下操作均建立在上篇文章sql Server操作1的数据基础之上 一.实验目的 熟悉SQL语句的基本使用方法,学习如何编写SQL语句来实现查询 二.实验内容和要求 使用SQL查询分析器查询数据,练 ...

  2. sqlserver查询某一字段重复超5次的所有记录

    用的sqlserver2008 r2. SELECT  * FROM t_class WHERE id IN (SELECT  id FROM (SELECT  ROW_NUMBER() OVER ( ...

  3. @Html.ValidationSummary()的使用

    @Html.ValidationSummary()用于返回表单在后台验证的结果. 如, 当后台if (ModelState.IsValid)失败后,错误信息就会显示到 @Html.Validation ...

  4. CentOS 修改默认语言

    查看所有的locale语言 [root@centos6 ~]# locale -a ... ... ... ... xh_ZA xh_ZA.iso88591 xh_ZA.utf8 yi_US yi_U ...

  5. Csharp多态的实现(抽象类)

    1.什么是抽象类 抽象类是虚拟的类,不能创建对象,用abstract修饰,在子类中用override进行重写 抽象类中可以存放抽象方法,属性,也可以存放非抽象方法,属性(这个在下面的代码可以看出来的) ...

  6. dp状态压缩-铺砖问题

    题目:有一个n行m列的地板,需要用 1*2小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法? 示范: 解法:用F[i][j]存放第i行的第j状态(j为十进制,转为二进制即是状态)有多少种方案. 用 ...

  7. leetcode Invert Binary Tree python

    # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = ...

  8. phpcms-v9 --- 如何通过{pc}标签获取全站文章内容?

    1.phpcms-v9默认情况下只能根据catid获取当前栏目及子栏目下的文章,但是有时候我们需要如何通过{pc}标签来获取全站文章内容的需求,应该怎么做呢? 第一步:在content_tag.cla ...

  9. javascript每日一练—运动

    1.弹性运动 运动原理:加速运动+减速运动+摩擦运动: <!doctype html> <html> <head> <meta charset="u ...

  10. OS X EI Capitan 10.11.1快速升级方法介绍

    公告:本文纯粹是给国内小水管用户而写的,如果你们家网络是100M光线那么就不需要看本文了! 一句话概要本文:在本地山寨从App store服务器上下载安装包的动作! 导读:OS X EI Capita ...