发生了火警,所有人员需要紧急疏散!假设每个房间是一个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
不会建图……Fuckstorm神犇(Orz)教的我
二分时间ans,每次二分把距离门的距离不超过ans的点和门之间连一条流量为1的边。
源点向每个’.’连一条流量为1的边,门向汇点连一条流量为ans的边。
但是好像被hack了…在黄学长博客 -> 在这:
4 5
XXDXX
XX.XX
X...X
XXDXX
其实也确实卡到我了…解决方法是把每个门拆成ans个点,每个点向他能连到的时间点连边(>=它到达门的最短时间)。
算法方面,网络流比较慢,所以改一下二分的上下界还是挺有必要的…数组memset也是,不要开太大…改完这俩我的程序快了近2000ms…
被hack的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int SZ = 10010;
const int INF = 1000000000;
const int dx[] = {0,0,1,0,-1};
const int dy[] = {0,1,0,-1,0};
int head[SZ],nxt[SZ],tot = 1,s,e;
struct edge{
int t,c;
}l[SZ];
inline void build(int f,int t,int c)
{
l[++tot] = (edge) {t,c};
nxt[tot] = head[f];
head[f] = tot;
}
queue<int> q;
int deep[SZ];
inline bool bfs()
{
memset(deep,0,sizeof(deep));
deep[s] = 1;
q.push(s);
while(q.size())
{
int f = q.front(); q.pop();
for(int i = head[f];i;i = nxt[i])
{
int v = l[i].t;
if(l[i].c && !deep[v])
{
deep[v] = deep[f] + 1;
q.push(v);
}
}
}
if(deep[e]) return true;
return false;
}
bool vv[SZ];
inline int dfs(int u,int flow)
{
if(u == e || flow == 0) return flow;
int ans = 0;
for(int i = head[u];i;i = nxt[i])
if(!vv[i])
{
int v = l[i].t;
if(l[i].c && deep[v] == deep[u] + 1)
{
vv[i] = 1;
int f = dfs(v,min(flow , l[i].c));
if(f > 0)
{
l[i].c -= f;
l[i ^ 1].c += f;
flow -= f;
ans += f;
vv[i] = 0;
}
if(flow == 0) break;
}
}
if(ans == 0) deep[u] = INF;
return ans;
}
inline int dinic()
{
int ans = 0;
while(bfs())
{
int tmp = dfs(s,INF);
if(tmp == 0) break;
ans += tmp;
memset(vv,0,sizeof(vv));
}
return ans;
}
int n,m,sum = 0;
char maps[233][233];
inline int getnode(int x,int y)
{
return (x - 1) * m + y;
}
struct xy{
int x,y,step;
};
queue<xy> que;
bool vis[233][233];
inline void bfs(int x,int y,int ans)
{
memset(vis,0,sizeof(vis));
que.push((xy){x,y,0});
while(que.size())
{
xy f = que.front(); que.pop();
if(f.step == ans) continue;
for(int i = 1;i <= 4;i ++)
{
int xx = f.x + dx[i];
int yy = f.y + dy[i];
if(xx > 0 && xx <= n && yy > 0 && yy <= m && maps[xx][yy] == '.' && !vis[xx][yy])
{
build(getnode(xx,yy),getnode(x,y),1); build(getnode(x,y),getnode(xx,yy),0);
vis[xx][yy] = 1;
que.push((xy){xx,yy,f.step + 1});
}
}
}
}
inline void init()
{
memset(head,0,sizeof(head));
memset(nxt,0,sizeof(nxt));
memset(l,0,sizeof(l));
tot = 1;
}
inline void build_graph(int ans)
{
init();
s = n * m + 1;
e = n * m + 2;
for(int x = 1;x <= n;x ++)
{
for(int y = 1;y <= m;y ++)
{
if(maps[x][y] == 'D')
{
bfs(x,y,ans);
build(getnode(x,y),e,ans);
build(e,getnode(x,y),0);
}
if(maps[x][y] == '.') build(s,getnode(x,y),1),build(getnode(x,y),s,0);
}
}
}
inline int div()
{
int r = 400 , l = -1;
while(r - l > 1)
{
int mid = (l + r) >> 1;
build_graph(mid);
// cout << dinic() <<endl;
if(dinic() >= sum) r = mid;
else l = mid;
}
return r;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)
{
scanf("%s",maps[i] + 1);
for(int j = 1;j <= m;j ++)
if(maps[i][j] == '.') sum ++;
}
int ans = div();
if(ans == 400) puts("impossible");
else printf("%d",ans);
return 0;
}
/* 20 3 XXX X.X X.D X.X X.X X.X D.X X.X D.X X.X X.X X.X X.X X.X X.X X.X X.X X.X X.X XXX */