bzoj1189: [HNOI2007]紧急疏散evacuate

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

3

HINT

2015.1.12新加数据一组,鸣谢1756500824

C++语言请用scanf("%s",s)读入!

题解:

先由S向每个有人的点连一条容量为1的边,然后二分时间t,对于每个每个门拆成t个点,每个点向T和下一个时间的点分别连容量为1和inf的边,表示这个门可以在每个时间里出来一个人,多余的人等到下一个时间

ps:网上的题解大多都是错的,反例去见黄学长博客里的评论

code:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cassert>
  5 #include<cstring>
  6 #include<algorithm>
  7 #define maxn 160000
  8 #define maxm 400000
  9 #define inf 1061109567
 10 using namespace std;
 11 char ch;
 12 bool ok;
 13 void read(int &x){
 14     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch==‘-‘) ok=1;
 15     for (x=0;isdigit(ch);x=x*10+ch-‘0‘,ch=getchar());
 16     if (ok) x=-x;
 17 }
 18 char graph[22][22];
 19 int n,m,cnt,pos[22][22],l,r,mid;
 20 struct flow{
 21     int s,t,idx,tot,now[maxn],son[maxm],pre[maxm],val[maxm];
 22     int dis[maxn],head,tail,list[maxn];
 23     bool bo[maxn];
 24     void init(){s=0,t=1,idx=1,tot=1,memset(now,0,sizeof(now));}
 25     void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
 26     void add(int a,int b,int c){put(a,b,c),put(b,a,0);}
 27     bool bfs(){
 28         memset(bo,0,sizeof(bo));
 29         head=0,tail=1,list[1]=s,bo[s]=1,dis[s]=0;
 30         while (head<tail){
 31             int u=list[++head];
 32             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
 33                 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v;
 34         }
 35         return bo[t];
 36     }
 37     int dfs(int u,int rest){
 38         if (u==t) return rest;
 39         int ans=0;
 40         for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p])
 41             if (val[p]&&dis[v]==dis[u]+1){
 42                 int d=dfs(v,min(rest,val[p]));
 43                 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d;
 44             }
 45         if (!ans) dis[u]=-1;
 46         return ans;
 47     }
 48     int dinic(){
 49         int ans=0;
 50         while (bfs()) ans+=dfs(s,inf);
 51         return ans;
 52     }
 53 }f,tmp;
 54 struct Point{
 55     int x,y,id;
 56 }list[405];
 57 int head,tail,g[405][405],dep[42][42];
 58 bool bo[42][42],flag;
 59 const int dx[4]={1,0,-1,0};
 60 const int dy[4]={0,1,0,-1};
 61 void bfs(int x,int y,int id){
 62     memset(bo,0,sizeof(bo));
 63     head=0,tail=1,list[1]=(Point){x,y,0},bo[x][y]=1,dep[x][y]=0;
 64     while (head<tail){
 65         Point p=list[++head];
 66         int d=dep[p.x][p.y];
 67         if (d) g[p.id][id]=d;
 68         for (int i=0;i<4;i++){
 69             int xx=p.x+dx[i],yy=p.y+dy[i];
 70             if (xx<=0||xx>n||yy<=0||yy>m||graph[xx][yy]!=‘.‘||bo[xx][yy]) continue;
 71             list[++tail]=(Point){xx,yy,pos[xx][yy]},bo[xx][yy]=1,dep[xx][yy]=d+1;
 72         }
 73     }
 74 }
 75 bool check(int lim){
 76     f=tmp;
 77     for (int i=2;i<=f.idx;i++) for (int j=1;j<=cnt;j++) if (g[i][j]<=lim&&g[i][j])
 78         f.add(i,f.idx+cnt*(g[i][j]-1)+j,1);
 79     for (int i=1;i<=cnt;i++) for (int j=1;j<=lim;j++){
 80         f.add(f.idx+cnt*(j-1)+i,f.t,1);
 81         if (j!=lim) f.add(f.idx+cnt*(j-1)+i,f.idx+cnt*j+i,inf);
 82     }
 83     return f.dinic()==f.idx-1;
 84 }
 85 int main(){
 86     read(n),read(m),f.init();
 87     for (int i=1;i<=n;i++) scanf("%s",graph[i]+1);
 88     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
 89         if (graph[i][j]==‘.‘) pos[i][j]=++f.idx,f.add(f.s,f.idx,1);
 90         else if (graph[i][j]==‘D‘) pos[i][j]=++cnt;
 91     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (graph[i][j]==‘D‘) bfs(i,j,pos[i][j]);
 92     for (int i=2;i<=f.idx;i++){
 93         bool fuck=1;
 94         for (int j=1;j<=cnt;j++) if (g[i][j]!=0) fuck=0;
 95         if (fuck){flag=1;break;}
 96     }
 97     if (flag){puts("impossible");return 0;}
 98     for (tmp=f,l=1,r=400,mid=(l+r)>>1;l<r;mid=(l+r)>>1) if (check(mid)) r=mid; else l=mid+1;
 99     printf("%d\n",l);
100     return 0;
101 }
时间: 2024-10-06 06:33:38

bzoj1189: [HNOI2007]紧急疏散evacuate的相关文章

BZOJ1189: [HNOI2007]紧急疏散evacuate 二分+最大流

1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1132  Solved: 412[Submit][Status][Discuss] Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且

bzoj千题计划132:bzoj1189: [HNOI2007]紧急疏散evacuate

http://www.lydsy.com/JudgeOnline/problem.php?id=1189 二分答案 源点向人连边,流量为1 门拆为mid个点,同一个门的第j个点向第j+1个点连边,流量为inf 若第i个人第k秒到达第j个门,第i个人向第j个门拆出的第k个点连边,流量为1 所有门向汇点连边,流量为1 用ISAP写的,真快,也真TM长 #include<queue> #include<cstdio> #include<algorithm> #include&

BZOJ1189 HNOI2007 紧急疏散evacuate 网络流+BFS+二分法

题意:一个N M的矩形区域.格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且边界上不会有空地.每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动.疏散开始后,每块空地上就没有人数限制.每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了.求所有的人安全撤离,最短需要多少时间 题解: 好神啊这题…… 首先我

【枚举】【二分答案】【分块答案】【BFS】【最大流】【Dinic】bzoj1189 [HNOI2007]紧急疏散evacuate

[法一]枚举Time(0~N*M): S->'.'(1); 'D'->T(Time); '.'->'D'(dis(用BFS预处理,注意一旦到达'D',BFS就不能继续扩展了,注意dis的初值0x7f)<=Time ? 1 : 0); 判断是否满流; #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; #d

【BZOJ1189】[HNOI2007]紧急疏散evacuate 动态加边网络流

[BZOJ1189][HNOI2007]紧急疏散evacuate Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且边界上不会有空地.最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动.疏散开始后,每块空地上就没有人数限制了(也就

BZOJ 1189: [HNOI2007]紧急疏散evacuate( BFS + 二分答案 + 匈牙利 )

我们可以BFS出每个出口到每个人的最短距离, 然后二分答案, 假设当前答案为m, 把一个出口拆成m个表示m个时间, 点u到出口v的距离为d, 那么u->v的[d, m]所有点连边, 然后跑匈牙利去check就行了...其实这道题挺好想但是码量还是挺大的.... ----------------------------------------------------------------------------- #include<cstdio> #include<cstring&

AC日记——[HNOI2007]紧急疏散evacuate bzoj 1189

[HNOI2007]紧急疏散evacuate 思路: 处理每个人到门的最短路: 然后二分答案: s向人连边流量1: 人向门拆分后的点连边流量1(拆成400,前一个点连当前点流量INF): 然后门向t连边流量二分的答案: 如果最后流量等于人的个数,则true: 来,上代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorit

[HNOI2007]紧急疏散EVACUATE (湖南2007年省选)

[HNOI2007]紧急疏散EVACUATE 题目描述 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且边界上不会有空地.最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动.疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人).

[HNOI2007]紧急疏散evacuate

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