3566 紧急疏散

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 黄金 Gold
 
 
题目描述 Description

发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。

输入描述 Input Description

输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。

输出描述 Output Description

只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出'impossible'(不包括引号).

样例输入 Sample Input

5 5  
XXXXX
X...D
XX.XX
X..XX
XXDXX

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

3<=N <=20,3<=M<=20

题解:

 对于每个门进行一次bfs,得出每个点到每个门的时间
 然后二分时间,每次建图dinic
 S到空地连一条容量1的边,
 每个空地到可到达的门连一条容量1的边,
 每个门到T连一条容量为时间的边

代码:

(对于codevs来说):

 #include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 0x7fffffff
#define maxn 1001
#define S 0
#define T 1000 using namespace std; int n,m,head[maxn],dis[][][],ans,tot,cnt=,door=,layered[maxn],map[][],finallyans=-;
int xx[]={,,,-},yy[]={,-,,}; struct ss
{
int x;
int y;
int s;
ss() {};
ss(int a,int b,int c)
{
x=a;
y=b;
s=c;
};
}; struct node
{
int to;
int next;
int edge;
}e[]; void add(int u,int v,int c)
{
e[++cnt].to=v;
e[cnt].next=head[u];
e[cnt].edge=c;
head[u]=cnt;
} void insert(int u,int v,int c)
{
add(u,v,c);
add(v,u,);
} bool bfs()
{
for (int i=;i<=T;i++) layered[i]=INF;
queue<int>que;
que.push(S);
while (!que.empty())
{
int now=que.front();
que.pop();
for (int i=head[now];i;i=e[i].next)
if (e[i].edge&&layered[e[i].to]>layered[now]+)
{
layered[e[i].to]=layered[now]+;
que.push(e[i].to);
if (e[i].to==T) return ;
}
}
return ;
} int dfs(int x,int inf)
{
if (x==T) return inf;
int rest=inf;
for (int i=head[x];i&&rest;i=e[i].next)
if (e[i].edge&&layered[e[i].to]==layered[x]+)
{
int now=dfs(e[i].to,min(rest,e[i].edge));
if (!layered[now]) layered[now]=;
e[i].edge-=now;
e[i^].edge+=now;
rest-=now;
}
return inf-rest;
} int dinic()
{
int ansn=;
while (bfs()) ansn+=dfs(S,INF);
return ansn;
} void built(int x)
{
memset(head,,sizeof (head));
cnt=;
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
if (map[i][j]==)
{
int v=(i-)*m+j;
insert(S,v,);
}
for (int i=;i<=door;i++) insert(n*m+i,T,x);
for (int i=;i<=door;i++)
for (int j=;j<=n;j++)
for (int k=;k<=m;k++)
if (dis[i][j][k]<=x) insert((j-)*m+k,n*m+i,x);
} bool judge(int x)
{
built(x);
int ans=dinic();
if (ans==tot) return ;
else return ;
} void search(int k,int x,int y)
{
queue<ss>que;
que.push(ss(x,y,));
while (!que.empty())
{
for (int i=;i<;i++)
{
int nowx=que.front().x+xx[i];
int nowy=que.front().y+yy[i];
int s=que.front().s;
if(nowx<||nowy<||nowx>n||nowy>m||map[nowx][nowy]!=) continue;
if (dis[k][nowx][nowy]==INF)
{
dis[k][nowx][nowy]=s+;
que.push(ss(nowx,nowy,s+));
}
}
que.pop();
}
}
int main()
{
char ch[];
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
{
scanf("%s",ch);
for (int j=;j<=m;j++)
{
if (ch[j-]=='.') map[i][j]=,tot++;
if (ch[j-]=='D') map[i][j]=++door;
}
}
for (int i=;i<=door;i++)
for (int j=;j<=n;j++)
for (int k=;k<=m;k++)
dis[i][j][k]=INF;
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
if (map[i][j]>) search(map[i][j],i,j);
int l=,r=;
while (l<=r)
{
int mid=(l+r)>>;
if (judge(mid)) finallyans=r=mid,r--;
else l=mid+;
}
if (finallyans==-) printf("impossible");
else printf("%d",finallyans);
return ;
}

对于bzoj来说:

 #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mid (l+r)/2
#define inf 0x7fffffff
#define T n*n*m*m+2
const int N=;
const int M=;
char s[N];
bool use[N][N],flag[N][N];
struct S{int x,y,c;}l[N*N];
struct Q{int st,en,va;}aa[M*];
int n,m,map[N][N],f[N][N][N][N],sum,point[M],next[M*],cur[M],dis[M],pre[M],gap[M],tot;
int xi[]={-,,,},yi[]={,-,,};
inline void bfs(int xa,int ya){
int i,h,t,k,x,y;
memset(use,,sizeof(use));
h=t=;l[h].x=xa;l[h].y=ya;l[h].c=;
while(h<=t){
x=l[h].x;y=l[h].y;
for(i=;i<;++i){
int xx=x+xi[i],yy=y+yi[i];
if(xx>&&xx<=n&&yy>&&y<=m&&map[xx][yy]==&&use[xx][yy]){
l[++t].x=xx;l[t].y=yy;l[t].c=l[h].c+;
use[xx][yy]=false;
f[xx][yy][xa][ya]=l[t].c;
flag[xx][yy]=true;
}
}
h+=;
}
}
inline void add(int x,int y,int z){
tot+=;next[tot]=point[x];point[x]=tot;
aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
tot+=;next[tot]=point[y];point[y]=tot;
aa[tot].st=y;aa[tot].en=x;aa[tot].va=;
}
inline int ISAP(int ss,int tt){
bool f;
int minn,ans=,i,u,y;
memset(dis,,sizeof(dis));
memset(gap,,sizeof(gap));
memset(pre,,sizeof(pre));
gap[]=tt-ss+; u=ss;
for(i=ss;i<=tt;++i) cur[i]=point[i];
while(dis[ss]<tt-ss+){
f=false;
for(i=cur[u];i;i=next[i])
if(aa[i].va>&&dis[u]==dis[aa[i].en]+){
cur[u]=i;f=true;break;
}
if(f){
pre[u=aa[i].en]=i;
if(u==tt){
minn=inf;
for(i=u;i!=ss;i=aa[pre[i]].st)
minn=min(minn,aa[pre[i]].va);
ans+=minn;
for(i=u;i!=ss;i=aa[pre[i]].st){
aa[pre[i]].va-=minn;
aa[pre[i]^].va+=minn;
}
u=ss;
}
}
else{
--gap[dis[u]];
if(!gap[dis[u]]) return ans;
y=*tt; cur[u]=point[u];
for(i=point[u];i;i=next[i])
if(aa[i].va>) y=min(y,dis[aa[i].st]);
++gap[dis[u]=y+];
if(u!=ss) u=aa[pre[u]].st;
}
}
return ans;
}
inline bool check(int x){
int i,j,p,q;
tot=;
memset(point,,sizeof(point));
memset(next,,sizeof(next));
for(i=;i<=n;++i)
for(j=;j<=m;++j){
int now=((i-)*m+j-)*n*m;
if(map[i][j]==){
for(p=;p<x;++p)
add(now+p+,now+p+,inf),add(now+p+,T,);
add(now+x+,T,);
}
if(map[i][j]==){
add(,now+,);
for(p=;p<=n;++p)
for(q=;q<=m;++q)
if(f[i][j][p][q])
add(now+,((p-)*m+q-)*n*m+f[i][j][p][q]+,);
}
}
return ISAP(,T)==sum;
}
int main(){
int i,j;
scanf("%d%d",&n,&m);
for(i=;i<=n;++i){
scanf("%s",&s);
for(j=;j<m;++j){
if(s[j]=='D') map[i][j+]=;
if(s[j]=='.') map[i][j+]=,sum+=;
if(s[j]=='X') map[i][j+]=;
}
}
for(i=;i<=n;++i)
for(j=;j<=m;++j)
if(map[i][j]==)
bfs(i,j);
for(i=;i<=n;++i)
for(j=;j<=m;++j)
if(!flag[i][j]&&map[i][j]==){
printf("impossible\n");
return ;
}
int l=,r=n*m,ans=inf;
while(l<r){
if(check(mid)) ans=min(ans,mid),r=mid;
else l=mid+;
}
printf("%d\n",ans);
}

C++之路进阶——codevs3566(紧急疏散)的更多相关文章

  1. C++之路进阶codevs1269(匈牙利游戏)

    1269 匈牙利游戏 2012年CCC加拿大高中生信息学奥赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description ...

  2. C++之路进阶——优先队列优化最短路径算法(dijkstra)

    一般的dijkstra算法利用贪心的思想,每次找出最短边,然后优化到其他点的的距离,我们还采用贪心思路,但在寻找最短边进行优化,之前是双重for循环,现在我们用优先队列来实现. 代码解释: //样例程 ...

  3. C++之路进阶——HDU1880(魔咒词典)

    ---恢复内容开始--- New~ 欢迎参加2016多校联合训练的同学们~ 魔咒词典 Time Limit: 8000/5000 MS (Java/Others)    Memory Limit: 3 ...

  4. C++之路进阶——poj3461(Oulipo)

    Oulipo Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 35694   Accepted: 14424 Descript ...

  5. C++之路进阶——P2022

    P2022 有趣的数 让我们来考虑1到N的正整数集合.让我们把集合中的元素按照字典序排列,例如当N=11时,其顺序应该为:1,10,11,2,3,4,5,6,7,8,9. 定义K在N个数中的位置为Q( ...

  6. C++之路进阶codevs1242(布局)

    1242 布局 2005年USACO  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold    <:section class="hbox" ...

  7. C++之路进阶——codevs3333(高级打字机)

    3333 高级打字机  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 大师 Master     题目描述 Description 早苗入手了最新的高级打字机.最新款自然有着与 ...

  8. C++之路进阶——codevs1789(最大获利)

    1789 最大获利 2006年NOI全国竞赛  时间限制: 2 s  空间限制: 128000 KB  题目等级 : 大师 Master       题目描述 Description 新的技术正冲击着 ...

  9. C++之路进阶——codevs2306(晨跑)

    2306 晨跑 2009年省队选拔赛山东  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 大师 Master       题目描述 Description Elaxia最近迷恋 ...

随机推荐

  1. VBA找不到progress bar的处理办法。

    Search your pc for MSCOMCTL.Ocx. If you find it then register it by clicking on Windows Start Button ...

  2. EL函数以及自定义标签的应用

    一.EL函数(调用普通类的静态方法) 编写步骤(自定义EL函数的编写步骤即自定义标签的编写步骤): ①编写一个普通的java类,提供一个静态方法,功能自定,例如下: package cn.wzbril ...

  3. iOS二维码生成-libqrencode编译报错

    libqrencode使用 1.将libqrencode文件夹整个拖入项目文件夹中 2.在要生成二维码的页面的 .m文件头部添加 #import "QRCodeGenerator.h&quo ...

  4. mysql缓存、存储引擎

    一.         mysql查询缓存 查询缓存不是mysql的子系统,却是查询优化和执行子系统不可缺少的组成部分.它不仅可以缓存查询结果,还可以缓存查询结果本身.如果某个查询的结果就在缓存里, 系 ...

  5. 了解学习JS中this的指向

    [转] 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问 ...

  6. 李洪强iOS经典面试题143-绘图与动画

    李洪强iOS经典面试题143-绘图与动画   绘图与动画 CAAnimation的层级结构 CAPropertyAnimation是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使 ...

  7. java并发编程(一)可重入内置锁

    每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁.线程在进入同步代码块之前会自动获取锁,并且在退出同步代码块时会自动释放锁.获得内置锁的唯一途径就是进入由这个锁保护的同步代码块 ...

  8. 不安装Oracle客户端使用PLSQL连接Oracle数据库的方法

    1,下载PL\SQL http://dl8.cr173.com/soft1/PLSQLDeveloper10_ha.zip(这个是我下载的,带破解和汉化); 2,下载完后傻瓜式安装 ,这里说下,1是P ...

  9. Unity学习疑问记录之将图切割保存

    http://blog.csdn.net/poem_of_sunshine/article/details/43036553

  10. Grandle全局变量定义及引用

    在Project的build.gradle脚本中定义一些全局变量 ext { compileSdkVersion = 21 buildToolsVersion = "24.0.1" ...