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. HDU-1203(01背包)

    I NEED A OFFER! Problem Description Speakless 很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了.要申请国外的 ...

  2. phpunit测试学习 1:一点简单的扼要有用的东西的总结 一点入门认识

    16:45 2015/12/8phpunit测试学习 1:一点简单的扼要有用的东西的总结  一点入门认识 具体的入门安装和入门实践请参照文中的推荐博客或网上其他博客推荐博客,我感觉这几篇博客写得很不错 ...

  3. 我JSP学习心得1

    老师布置了一项作业,说是要按着老师的要求写,但我觉得只要是技术分享的心得就是好的,不论是不是所要求的内容. 由于和几个人在外面给别人搭建网站,项目需要学习了jsp有用到了javascript,这里有一 ...

  4. HTML—marquee

    滚动标签 支持的属性: 1.align 2.behavior: alternate: 表示在两端之间来回滚动.scroll: 表示由一端滚动到另一端,会重复.slide:  表示由一端滚动到另一端,不 ...

  5. mysql数据库封装

    <?php /** * name: sql操作封装,可扩展 . * User: 张云山 * Date: 2016/9/4 * Time: 22:02 */ //php文件编码设置header(' ...

  6. 局域网内利用gitlab,jenkins自动生成gitbook并发布(nginx)

    安装了GitBook,内网使用,没法用上gitbook的网页. 用gitbook serve只能展示一本书,而且也不利于长期维护. 于是使用gitlab,jenkins,和nginx配合gitbook ...

  7. 完成对数据库的CRUD操作

    PS:查询相对复杂,要处理结果集,增删改则不用. package it.cast.jdbc; import java.sql.Connection; import java.sql.ResultSet ...

  8. canvas中的rotate的使用方法

    今天在绘制一个足球滚动的时候,想使用rotate方法,之前看到这个方法的时候,并没有引起任何重视,无非就是和CSS3里的rotate一样的用么... 遗憾的是,事实并非如此,由于代码在公司,我也就不去 ...

  9. java工程师 学习路线图

  10. WebApp中的页面生命周期及路由管理

    最近切换到一个新项目,使用的技术栈是Require+Backbone,鉴于对鞋厂webapp框架的了解,发现这个新项目有些缺陷,主要是单纯依赖Backbone造成的,也就是Backbone的好和坏都在 ...