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
XXXXX
X...D
XX.XX
X..XX
XXDXX
Sample Output
3
Solution
$Update$:写假了,先别看了QwQ
这个题……有点像跳舞那个题emmmm……
答案肯定是满足单调性的,所以我们可以枚举
(可以和跳舞那个题一样二分,不过二分就要每次重新添加边,太麻烦)
先判断impossible,BFS判断就行。
建图:超级源点-人-门-超级汇点
枚举秒数,每一秒就在门和超级汇点间连一条容量1的边,意味着当前秒这个门可以多出一个人了
若某个人到某个门耗费的时间为当前秒数,就在人和门间连一条容量为1的边
之后跑一边最大流,若最大流为人数的话就说明人可以全跑出去了
PS每次跑最大流的时候之前的Ans不能清零emmm
答案肯定是满足单调性的,所以我们可以枚举
(可以和跳舞那个题一样二分,不过二分就要每次重新添加边,太麻烦)
先判断impossible,BFS判断就行。
建图:超级源点-人-门-超级汇点
枚举秒数,每一秒就在门和超级汇点间连一条容量1的边,意味着当前秒这个门可以多出一个人了
若某个人到某个门耗费的时间为当前秒数,就在人和门间连一条容量为1的边
之后跑一边最大流,若最大流为人数的话就说明人可以全跑出去了
PS每次跑最大流的时候之前的Ans不能清零emmm
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #define MAXM (100000+10) 7 #define MAXN (1010+10) 8 using namespace std; 9 struct node 10 { 11 int Flow; 12 int next; 13 int to; 14 }edge[MAXM*2]; 15 int Depth[MAXN],Q[MAXN]; 16 int head[MAXN],num_edge; 17 int n,m,s,e=999,d,INF; 18 int a[MAXN][MAXN]; 19 int num[MAXN][MAXN]; 20 int dis[MAXN][MAXN]; 21 int PEOPLE[MAXN],P_sum; 22 int DOOR[MAXN],D_sum; 23 int dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1}; 24 int q[1005][3]; 25 int Ans; 26 bool used[505][505]; 27 char ch[1005]; 28 29 void add(int u,int v,int l) 30 { 31 edge[++num_edge].to=v; 32 edge[num_edge].Flow=l; 33 edge[num_edge].next=head[u]; 34 head[u]=num_edge; 35 } 36 37 bool Bfs(int s,int e) 38 { 39 int Head=0,Tail=1; 40 memset(Depth,0,sizeof(Depth)); 41 Depth[s]=1; 42 Q[1]=s; 43 while (Head<Tail) 44 { 45 int x=Q[++Head]; 46 for (int i=head[x];i!=0;i=edge[i].next) 47 if (!Depth[edge[i].to] && edge[i].Flow>0) 48 { 49 Depth[edge[i].to]=Depth[x]+1; 50 Q[++Tail]=edge[i].to; 51 } 52 } 53 if (Depth[e]>0) return true; 54 return false; 55 } 56 57 int Dfs(int x,int low) 58 { 59 int Min,f=0; 60 if (x==e || low==0) 61 return low; 62 for (int i=head[x];i!=0;i=edge[i].next) 63 if (edge[i].Flow>0 && Depth[edge[i].to]==Depth[x]+1 && (Min=Dfs(edge[i].to , min(low,edge[i].Flow) ))) 64 { 65 edge[i].Flow-=Min; 66 edge[((i-1)^1)+1].Flow+=Min; 67 f+=Min; 68 low-=Min; 69 } 70 return f; 71 } 72 73 int Dinic(int s,int e) 74 { 75 // int Ans=0; 76 while (Bfs(s,e)) 77 Ans+=Dfs(s,0x7fffffff); 78 return Ans; 79 } 80 81 void DISTANCE(int x,int y) 82 { 83 int Head=0,Tail=1; 84 memset(used,false,sizeof(used)); 85 q[1][1]=x; 86 q[1][2]=y; 87 used[x][y]=true; 88 while (Head<Tail) 89 { 90 ++Head; 91 for (int i=1;i<=4;++i) 92 { 93 int xx=q[Head][1]+dx[i]; 94 int yy=q[Head][2]+dy[i]; 95 if (!used[xx][yy] && a[xx][yy]) 96 { 97 used[xx][yy]=true; 98 dis[num[x][y]][num[xx][yy]]=dis[num[x][y]][num[q[Head][1]][q[Head][2]]]+1; 99 q[++Tail][1]=xx; 100 q[Tail][2]=yy; 101 } 102 } 103 } 104 } 105 106 int main() 107 { 108 memset(&INF,0x7f,sizeof(INF)); 109 int n,m,cnt=0; 110 scanf("%d%d",&n,&m); 111 for (int i=1;i<=n;++i) 112 { 113 scanf("%s",ch); 114 for (int j=1;j<=m;++j) 115 { 116 if (ch[j-1]=='X') 117 continue; 118 num[i][j]=++cnt; 119 if (ch[j-1]=='.') 120 { 121 a[i][j]=1; 122 PEOPLE[++P_sum]=num[i][j]; 123 } 124 else 125 { 126 a[i][j]=2; 127 DOOR[++D_sum]=num[i][j]; 128 } 129 } 130 } 131 for (int i=1;i<=n;++i) 132 for (int j=1;j<=m;++j) 133 if (a[i][j]) 134 DISTANCE(i,j); 135 for (int i=1;i<=P_sum;++i) 136 { 137 bool flag=false; 138 for (int j=1;j<=D_sum;++j) 139 if (dis[PEOPLE[i]][DOOR[j]]!=0) 140 { 141 flag=true; 142 break; 143 } 144 if (!flag) 145 { 146 printf("impossible\n"); 147 return 0; 148 } 149 } 150 for (int i=1;i<=P_sum;++i) 151 { 152 add(0,PEOPLE[i],1); 153 add(PEOPLE[i],0,0); 154 } 155 for (int i=1;i<=99999999;++i) 156 { 157 for (int j=1;j<=D_sum;++j) 158 { 159 add(DOOR[j],999,1); 160 add(999,DOOR[j],0); 161 } 162 for (int j=1;j<=P_sum;++j) 163 for (int k=1;k<=D_sum;++k) 164 if (dis[PEOPLE[j]][DOOR[k]]==i) 165 { 166 add(PEOPLE[j],DOOR[k],1); 167 add(DOOR[k],PEOPLE[j],0); 168 } 169 if (Dinic(0,999)==P_sum) 170 { 171 printf("%d",i); 172 return 0; 173 } 174 } 175 }