C++之路进阶——codevs3566(紧急疏散)
3566 紧急疏散
发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。
只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出'impossible'(不包括引号).
5 5
XXXXX
X...D
XX.XX
X..XX
XXDXX
3
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(紧急疏散)的更多相关文章
- C++之路进阶codevs1269(匈牙利游戏)
1269 匈牙利游戏 2012年CCC加拿大高中生信息学奥赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description ...
- C++之路进阶——优先队列优化最短路径算法(dijkstra)
一般的dijkstra算法利用贪心的思想,每次找出最短边,然后优化到其他点的的距离,我们还采用贪心思路,但在寻找最短边进行优化,之前是双重for循环,现在我们用优先队列来实现. 代码解释: //样例程 ...
- C++之路进阶——HDU1880(魔咒词典)
---恢复内容开始--- New~ 欢迎参加2016多校联合训练的同学们~ 魔咒词典 Time Limit: 8000/5000 MS (Java/Others) Memory Limit: 3 ...
- C++之路进阶——poj3461(Oulipo)
Oulipo Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 35694 Accepted: 14424 Descript ...
- C++之路进阶——P2022
P2022 有趣的数 让我们来考虑1到N的正整数集合.让我们把集合中的元素按照字典序排列,例如当N=11时,其顺序应该为:1,10,11,2,3,4,5,6,7,8,9. 定义K在N个数中的位置为Q( ...
- C++之路进阶codevs1242(布局)
1242 布局 2005年USACO 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold <:section class="hbox" ...
- C++之路进阶——codevs3333(高级打字机)
3333 高级打字机 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 大师 Master 题目描述 Description 早苗入手了最新的高级打字机.最新款自然有着与 ...
- C++之路进阶——codevs1789(最大获利)
1789 最大获利 2006年NOI全国竞赛 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 新的技术正冲击着 ...
- C++之路进阶——codevs2306(晨跑)
2306 晨跑 2009年省队选拔赛山东 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 大师 Master 题目描述 Description Elaxia最近迷恋 ...
随机推荐
- ZeroMQ接口函数之 :zmq - 0MQ 轻量级消息传输内核
官方网址:http://api.zeromq.org/4-0:zmq zmq(7) 0MQ Manual - 0MQ/3.2.5 Name zmq – ØMQ 轻量级消息传输内核 Synopsis # ...
- VerifyCodeUtil.java
package com.vcredit.framework.utils; import java.awt.Color;import java.awt.Font;import java.awt.Grap ...
- JS全兼容检测浏览器类型及版本
直接上代码: <script> var browser = (function () { var isIE6 = /msie 6/i.test(navigator.userAgent); ...
- 重置dns
flusdns
- spring mvc异常统一处理(ControllerAdvice注解)
首先我的项目是一个为移动端提供的json数据的,当后台报错时如果为移动端返回一个错误页面显得非常不友好,于是通过ControllerAdvice注解返回json数据. 首先创建一个异常处理类: pac ...
- HTML5 头部标签定义
<!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...
- NC57,NC63-NC二开经验总结
版主2010级市场营销专业本科生 2013年8月入达内培训Java相关技术 12月入职,做用友NC的二次开发工作 2015年4月离职,4中下旬入职一家互联网金融企业 下面是做NC二开期间积累的一些常用 ...
- VECTOR COMPUTATION
COMPUTER OR GANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION Although the perform ...
- Symmetric Multiprocessor Organization
COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION
- 2在HTML中使用JavaScript
像HTML页面中插入JavaScrip的主要方法,就是使用<script>元素.HTML4.01为<script>定义了6个属性:async:可选,表示应该立即下载脚本,当不妨 ...