题目大意:有一个类似于迷宫搜索的图,‘.’代表的是无人的路,'X'代表有人的点,'#'代表此点不可通过,'@'代表门口。每个位置每一秒钟只能站一个人,每个位置到上下左右点的时间为1,问你所有人能不能出去,能出去输出所有人都出去的最小时间,否则输出-1.

链接:点我

A: 增加源点src,和汇点dest,然后根据每个时间点建出分层图,每个时间对应一层,对于每层图的构造如下

B:给每个格子标 上号Xi, 由于每个格子一次只能占一人,所以把每个格子分为两个点xa,xb,连上容量为1的有向边,对于格子为‘X’的,(如果为第0层的话)在源点src与xa 之间连一条容量为1的有向边,对于格子为'@'的点,在xb与汇点dest连上容量为1的有向边,对于每个格子,(除‘#’外),在xb与其上下左右及其本身 的对应下一层图的xa连上容量为1 的一条有向边

C:具体操作并不是一下子建出分层图,由于时间是未知的,所以枚举时间,做最大流,当最大流小于人数时,时间加一并在原图上增加一层,继续求最大流,直到最大流大于等于人数,这时的时间就是答案

原理懂了,代码也懂了,真自己敲估计还是很难敲出来,等专题训练吧

 /*HDU_1733 Escape*/
/*分层图网络流+枚举时间*/
/*AC代码:171ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#define MAXN 20005
#define Lim 75
#define INF (1<<30)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
struct Node
{
int x,y;
Node(int x1,int y1)
{x=x1;y=y1;}
Node(){}
};
struct edge
{
int u,v,w,next;
}E[];
int head[MAXN],ecnt;
int gap[MAXN],cur[MAXN],dis[MAXN],pre[MAXN];
int N,M,scr,sink,vn,Ti,Sum,now;
int ans;
int dir[][]={,,,-,,,-,,,};
char map[][];
Node Q[];
int Head,Tail;
bool vis[][];
void Insert(int u,int v,int w)
{
E[ecnt].u=u;
E[ecnt].v=v;
E[ecnt].w=w;
E[ecnt].next=head[u];
head[u]=ecnt++;
E[ecnt].u=v;
E[ecnt].v=u;
E[ecnt].w=;
E[ecnt].next=head[v];
head[v]=ecnt++;
}
bool BFS(Node s)
{
int i,j;
Node u,v;
memset(vis,false,sizeof(vis));
Head=Tail=;
vis[s.x][s.y]=true;
Q[Head++]=s;
while(Head!=Tail)
{
u=Q[Tail++];
if(map[u.x][u.y]=='@') return true;
for(i=;i<;i++)
{
int dx=u.x+dir[i][];
int dy=u.y+dir[i][];
if(dx>=&&dx<N&&dy>=&&dy<M&&map[dx][dy]!='#'&&!vis[dx][dy])
{
vis[dx][dy]=true;
Q[Head++]=Node(dx,dy);
}
}
}
return false;
}
bool OK()
{
bool ok=true;
Node s;
int i,j;
for(i=;i<N&&ok;i++)
{
for(j=;j<M;j++)
{
if(map[i][j]=='X')
{
s.x=i;s.y=j;
if(!BFS(s))
{
ok=false;
break;
}
}
}
}
return ok;
}
void Init()
{
int i,j,u;
memset(head,-,sizeof(head));ecnt=;
for(i=;i<N;i++)
scanf("%s",map[i]);
scr=;sink=;vn=;
Sum=;
for(i=;i<N;i++)
{
for(j=;j<M;j++)
{
if(map[i][j]=='X')
{
Sum++;
u=i*M+j+;
Insert(scr,u,);
}
}
}
now=(M*N);
vn+=now;
}
int Sap(int s,int t,int n)//核心代码(模版)
{
int ans=,aug=INF;//aug表示增广路的流量
int i,v,u=pre[s]=s;
for(i=;i<=n;i++)
{
cur[i]=head[i];
dis[i]=gap[i]=;
}
gap[s]=n;
bool flag;
while(dis[s]<n)
{
flag=false;
for(int &j=cur[u];j!=-;j=E[j].next)//一定要定义成int &j,why
{
v=E[j].v;
if(E[j].w>&&dis[u]==dis[v]+)
{
flag=true;//找到容许边
aug=min(aug,E[j].w);
pre[v]=u;
u=v;
if(u==t)
{
ans+=aug;
while(u!=s)
{
u=pre[u];
E[cur[u]].w-=aug;
E[cur[u]^].w+=aug;//注意
}
aug=INF;
}
break;//找到一条就退出
}
}
if(flag) continue;
int mindis=n;
for(i=head[u];i!=-;i=E[i].next)
{
v=E[i].v;
if(E[i].w>&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=i;
}
}
if((--gap[dis[u]])==) break;
gap[dis[u]=mindis+]++;
u=pre[u];
}
return ans;
} bool Judge(int Ti)
{
int i,j,k,u,v,a,b,dx,dy;
for(i=;i<N;i++)
{
for(j=;j<M;j++)
{
if(map[i][j]=='#') continue;
u=i*M+j+;
a=(Ti-)*N*M;
b=a+N*M;
u=a+u+;
for(k=;k<;k++)
{
dx=i+dir[k][];
dy=j+dir[k][];
if(dx>=&&dx<N&&dy>=&&dy<M&&map[dx][dy]!='#')
{
v=dx*M+dy+;
v=b+v+;
Insert(u,v,);
}
}
if(map[i][j]=='@')
{
v=b+i*M+j+;
Insert(v,sink,);
}
}
}
vn+=(N*M);
now+=(N*M); //这个now好像没啥用
int t=Sap(scr,sink,vn);
ans+=t;
return ans==Sum;
}
void Solve()
{
if(Sum==) {printf("0\n");return;}
if(!OK()) {printf("-1\n");return;}
ans=Ti=;
while(true)
{
Ti++;
if(Judge(Ti)) break;
}
printf("%d\n",Ti);
}
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
Init();
Solve();
}
return ;
}

hdu 1733 分层网络流 ****的更多相关文章

  1. hdu 2883 kebab 网络流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2883 Almost everyone likes kebabs nowadays (Here a ke ...

  2. SGU 438 The Glorious Karlutka River =) ★(动态+分层网络流)

    [题意]有一条东西向流淌的河,宽为W,河中有N块石头,每块石头的坐标(Xi, Yi)和最大承受人数Ci已知.现在有M个游客在河的南岸,他们想穿越这条河流,但是每个人每次最远只能跳D米,每跳一次耗时1秒 ...

  3. HDU 3452 Bonsai(网络流之最小割)

    题目地址:HDU 3452 最小割水题. 源点为根节点.再另设一汇点,汇点与叶子连边. 对叶子结点的推断是看度数是否为1. 代码例如以下: #include <iostream> #inc ...

  4. hdu 3572 Escape 网络流

    题目链接 给一个n*m的图, 里面有一些点, '.'代表空地, '#'代表墙, 不可以走, '@'代表大门, 可以有多个, 'X'代表人, 问所有人都走出大门需要的最短时间, 每一时刻一个格子只能有一 ...

  5. HDU 3667 Transportation(网络流之费用流)

    题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k.须要让每一次增广到的流量都是1,这就须要把每一条边的流量都是1才行.可是每条边的流量并非1,该怎么办呢.这个时候能够拆边,反 ...

  6. HDU 5988最小网络流(浮点数)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5988 哇,以前的模版一直T,加了优先队列优化才擦边过. 建图很好建,概率乘法化成概率加法不 ...

  7. Leapin' Lizards [HDU - 2732]【网络流最大流】

    题目链接 网络流直接最大流就是了,只是要拆点小心一个点的流超出了原本的正常范围才是. #include <iostream> #include <cstdio> #includ ...

  8. hdu 4292 Food 网络流

    题目链接 给你f种食物, 以及每种食物的个数, d种饮料, 以及个数, n个人, 以及每个人可以接受的食物种类和饮料种类. 每个人必须得到一种食物和一种饮料. 问最后得到满足的人的个数. 因为一个人只 ...

  9. hdu 4289 Control 网络流

    题目链接 给出一些点, 每个点有一个权值, 给出一些边, 起点以及终点, 去掉一些点使得起点和终点不连通, 求最小的val. 拆点, 把一个点s拆成s和s', 之间建一条边, 权值为点权. 对于一条边 ...

随机推荐

  1. visual studio 2010 破解版 破解方法

    1.Microsoft Visual Studio 2010下载(均来自微软官网) 高级版(Premium) [建议下载]       http://download.microsoft.com/do ...

  2. MySQL获取随机数

    如何通过MySQL在某个数据区间获取随机数? MySQL本身提供一个叫rand的函数,返回的v范围为0 <= v < 1.0. 介绍此函数的MySQL文档也介绍道,可以通过此计算公式FLO ...

  3. ES6的promise对象研究

    ES6的promise对象研究 什么叫promise? Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码:让代码更加的直观. 那我们为什么 ...

  4. TYVJ1460 旅行

    描述 A国有n座城市,每座城市都十分美,这使得A国的民众们非常喜欢旅行.然而,A国的交通十分落后,这里只有m条双向的道路,并且这些道路都十分崎岖,有的甚至还是山路,只能靠步行.通过每条道路的长度.泥泞 ...

  5. 一个PHP写的简单webservice服务端+客户端

    首先是服务端,服务端有一个主要的class组成:apiServer.php <?php /** * apiServer.php * * webservice主类 * * @filename ap ...

  6. Linux大神必备-文本编辑器

    导读 我们在 Linux 上不缺乏非常现代化的编辑软件,但是它们都是基于 GUI(图形界面)的编辑软件.正如你所了解的:Linux 真正的魅力在于命令行,当你正在用命令行工作时,你就需要一个可以在控制 ...

  7. DrawText

    该函数在指定的矩形里写入格式化的正文,根据指定的方法对正文格式化(扩展的制表符,字符对齐.折行等).   int DrawText(HDC hDC, // 设备描述表句柄 LPCTSTR lpStri ...

  8. Linux Apache prefork和worker的原理详解

    prefork(多进程,每个进程产生子进程)和worker(多进程,每个进程生成多个线程)    prefork的工作原理是,控制进程在最初建立“StartServers”个子进程后,为了满足MinS ...

  9. python 异步线程简单实现

    import threading def foo(): with open(r'./result.log','wb') as f: f.write('=some logs here ==') t = ...

  10. PHP中冒号、endif、endwhile、endfor这些都是什么

    我们经常在wordpress一类博客程序的模板里面看到很多奇怪的PHP语法,比如:<?php if(empty($GET_['a'])): ?><font color="r ...