紧急疏散evacuate

1689: [HNOI2007]紧急疏散evacuate

题目描述

发生了火警,所有人员需要紧急疏散!假设每个房间是一个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

  一道网络流的题:我们发现时间是满足单调性的,所以可以二分时间logn的复杂度,在当前时间限制下,将原点与每个人相连,每个人于能到达的不同时刻的每个门相连,意思是要将每个门拆点,拆成在不同时刻的门。所以要预处理出每个人到每个门的最短距离,跑一边dfs,再由这些门与汇点相连,这些边的容量为一;在这道题上炮最大流就行了,当且仅当最大流的数值等于总人数是,此时间点是可行的。  如果最终结果为你二分的上界的话:意思是没有这种情况,cout<<impossible;所以上界要定的稍大一些;

附代码:  
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<map>
  6 #include<queue>
  7 using namespace std;
  8 #define inf 5000000
  9 map<pair<int,int>,int>ma;
 10 int n,m,num,cnt,shu;
 11 int pos[21][21],id[21][21],dis[401][401];
 12 char s[21][21];int adj[10002];
 13 struct flow{
 14     int s,t,w,next;
 15 }k[2000001];
 16 int read(){
 17     int sum=0;char ch=getchar();
 18     while(ch<‘0‘||ch>‘9‘) ch=getchar();
 19     while(ch>=‘0‘&&ch<=‘9‘){sum=sum*10+ch-‘0‘;ch=getchar();}
 20     return sum;
 21 }
 22 void dfs(int fa,int cnt,int x,int y){
 23     if(pos[x-1][y]==1){
 24         if(dis[fa][id[x-1][y]]>dis[fa][cnt]+1){
 25             dis[fa][id[x-1][y]]=dis[fa][cnt]+1;
 26             dfs(fa,id[x-1][y],x-1,y);
 27         }
 28     }
 29     if(pos[x+1][y]==1){
 30         if(dis[fa][id[x+1][y]]>dis[fa][cnt]+1){
 31             dis[fa][id[x+1][y]]=dis[fa][cnt]+1;
 32             dfs(fa,id[x+1][y],x+1,y);
 33         }
 34     }
 35     if(pos[x][y-1]==1){
 36         if(dis[fa][id[x][y-1]]>dis[fa][cnt]+1){
 37             dis[fa][id[x][y-1]]=dis[fa][cnt]+1;
 38             dfs(fa,id[x][y-1],x,y-1);
 39         }
 40     }
 41     if(pos[x][y+1]==1){
 42         if(dis[fa][id[x][y+1]]>dis[fa][cnt]+1){
 43             dis[fa][id[x][y+1]]=dis[fa][cnt]+1;
 44             dfs(fa,id[x][y+1],x,y+1);
 45         }
 46     }
 47 }
 48 void search(int x,int y){
 49     dis[id[x][y]][id[x][y]]=0;
 50     dfs(id[x][y],id[x][y],x,y);
 51 }
 52 void init(int s,int t,int w){
 53     k[num].s=s;k[num].t=t;k[num].w=w;
 54     k[num].next=adj[s];adj[s]=num++;
 55 }
 56 void build(int lim){
 57     num=0;memset(adj,-1,sizeof(adj));
 58     for(int i=1;i<=n;++i)
 59         for(int j=1;j<=m;++j){
 60             if(pos[i][j]==1)
 61                 init(0,id[i][j],1),init(id[i][j],0,0);
 62             if(pos[i][j]==2){
 63                 for(int u=1;u<=lim;++u)
 64                     init(ma[make_pair(id[i][j],u)],10000,1),init(10000,ma[make_pair(id[i][j],u)],0);
 65                 for(int u=1;u<=n;++u)
 66                     for(int p=1;p<=m;++p)
 67                         if(pos[u][p]==1)
 68                             for(int b=dis[id[i][j]][id[u][p]];b<=lim;++b)
 69                                 init(id[u][p],ma[make_pair(id[i][j],b)],1),init(ma[make_pair(id[i][j],b)],id[u][p],0);                      }
 70     }
 71 }
 72 int dp[10001];
 73 bool bfs(){
 74     memset(dp,0,sizeof(dp));
 75     queue<int>q;
 76     q.push(0);dp[0]=1;
 77     while(!q.empty()){
 78         int o=q.front();q.pop();
 79         for(int i=adj[o];i!=-1;i=k[i].next){
 80             if(!k[i].w||dp[k[i].t]) continue;
 81             dp[k[i].t]=dp[o]+1;
 82             if(k[i].t==10000) return true;
 83             q.push(k[i].t);
 84         }
 85     }
 86     return false;
 87 }
 88 int Dfs(int o,int fw){
 89     if(o==10000) return fw;
 90     int tmp=fw,u;
 91     for(int i=adj[o];i!=-1;i=k[i].next){
 92         if(!k[i].w||!tmp||dp[k[i].t]!=dp[o]+1) continue;
 93         u=Dfs(k[i].t,min(k[i].w,tmp));
 94         if(!u){
 95             dp[k[i].t]=0;continue;
 96         }
 97         k[i].w-=u;k[i^1].w+=u;tmp-=u;
 98     }
 99     return fw-tmp;
100 }
101 bool judge(int ti){
102     build(ti);
103     int ans=0;
104     while(bfs())
105         ans+=Dfs(0,inf);
106     if(ans==shu) return true;
107     else return false;
108 }
109 int erfen(int l,int r){
110     if(l==r) return l;
111     int mid=(l+r)>>1;
112     if(judge(mid))
113         return erfen(l,mid);
114     else
115         return erfen(mid+1,r);
116 }
117 int main(){
118    // freopen("a.in","r",stdin);
119    // freopen("a.out","w",stdout);
120     n=read();m=read();
121     memset(adj,-1,sizeof(adj));
122     memset(pos,0x3f,sizeof(pos));
123     memset(dis,0x3f,sizeof(dis));
124     for(int i=1;i<=n;++i)
125         scanf("%s",s[i]);
126     for(int i=1;i<=n;++i)
127         for(int j=1;j<=m;++j)
128             if(s[i][j-1]==‘D‘)
129                 pos[i][j]=2,id[i][j]=++cnt;
130             else if(s[i][j-1]==‘.‘)
131                 pos[i][j]=1,id[i][j]=++cnt,shu++;
132     cnt=n*m;
133     for(int i=1;i<=n;++i)
134         for(int j=1;j<=m;++j)
135             if(pos[i][j]==2)
136                 for(int u=1;u<=200;++u)
137                     ma[make_pair(id[i][j],u)]=++cnt;
138     for(int i=1;i<=n;++i)
139         for(int j=1;j<=m;++j)
140             if(pos[i][j]==2)
141                 search(i,j);
142     int ans=erfen(0,200);
143     if(ans==200) printf("impossible");
144     else  printf("%d\n",ans);
145     return 0;
146 }
 
时间: 2024-12-22 21:29:16

紧急疏散evacuate的相关文章

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

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',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且

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

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

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

[HNOI2007]紧急疏散EVACUATE 题目描述 发生了火警,所有人员需要紧急疏散!假设每个房间是一个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&

[HNOI2007]紧急疏散evacuate

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

BZOJ 1189 【HNOI2007】 紧急疏散evacuate

题目链接:紧急疏散 这薄脊题我代码不知不觉就写长了-- 这道题二分答案显然,然后用最大流\(check\)即可.设当前二分的答案为\(x\),那么把每扇门拆成\(x\)个点,第\(i\)个代表在第\(i\)个时刻从这个门走出去.然后把每个空地往可以到达的们的相应时间连边就可以了.判一下这张图是否满流即可. 然后我们就需要先求出每个空地到门的距离--注意途中不能经过另外的门,否则会被BZOJ上加强的数据给卡掉-- 下面贴代码: #include<iostream> #include<cst

bzoj1189: [HNOI2007]紧急疏散evacuate

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