题目大意:有一个类似于迷宫搜索的图,‘.’代表的是无人的路,'X'代表有人的点,'#'代表此点不可通过,'@'代表门口。每个位置每一秒钟只能站一个人,每个位置到上下左右点的时间为1,问你所有人能不能出去,能出去输出所有人都出去的最小时间,否则输出-1.
链接:点我
A: 增加源点src,和汇点dest,然后根据每个时间点建出分层图,每个时间对应一层,对于每层图的构造如下
B:给每个格子标 上号Xi, 由于每个格子一次只能占一人,所以把每个格子分为两个点xa,xb,连上容量为1的有向边,对于格子为‘X’的,(如果为第0层的话)在源点src与xa 之间连一条容量为1的有向边,对于格子为'@'的点,在xb与汇点dest连上容量为1的有向边,对于每个格子,(除‘#’外),在xb与其上下左右及其本身 的对应下一层图的xa连上容量为1 的一条有向边
C:具体操作并不是一下子建出分层图,由于时间是未知的,所以枚举时间,做最大流,当最大流小于人数时,时间加一并在原图上增加一层,继续求最大流,直到最大流大于等于人数,这时的时间就是答案
原理懂了,代码也懂了,真自己敲估计还是很难敲出来,等专题训练吧
1 /*HDU_1733 Escape*/ 2 /*分层图网络流+枚举时间*/ 3 /*AC代码:171ms*/ 4 #include <iostream> 5 #include <cstdio> 6 #include <memory.h> 7 #include <algorithm> 8 #define MAXN 20005 9 #define Lim 75 10 #define INF (1<<30) 11 #define max(a,b) (a>b?a:b) 12 #define min(a,b) (a<b?a:b) 13 using namespace std; 14 struct Node 15 { 16 int x,y; 17 Node(int x1,int y1) 18 {x=x1;y=y1;} 19 Node(){} 20 }; 21 struct edge 22 { 23 int u,v,w,next; 24 }E[2000000]; 25 int head[MAXN],ecnt; 26 int gap[MAXN],cur[MAXN],dis[MAXN],pre[MAXN]; 27 int N,M,scr,sink,vn,Ti,Sum,now; 28 int ans; 29 int dir[5][2]={0,1,0,-1,1,0,-1,0,0,0}; 30 char map[20][20]; 31 Node Q[200000]; 32 int Head,Tail; 33 bool vis[20][20]; 34 void Insert(int u,int v,int w) 35 { 36 E[ecnt].u=u; 37 E[ecnt].v=v; 38 E[ecnt].w=w; 39 E[ecnt].next=head[u]; 40 head[u]=ecnt++; 41 E[ecnt].u=v; 42 E[ecnt].v=u; 43 E[ecnt].w=0; 44 E[ecnt].next=head[v]; 45 head[v]=ecnt++; 46 } 47 bool BFS(Node s) 48 { 49 int i,j; 50 Node u,v; 51 memset(vis,false,sizeof(vis)); 52 Head=Tail=0; 53 vis[s.x][s.y]=true; 54 Q[Head++]=s; 55 while(Head!=Tail) 56 { 57 u=Q[Tail++]; 58 if(map[u.x][u.y]=='@') return true; 59 for(i=0;i<4;i++) 60 { 61 int dx=u.x+dir[i][0]; 62 int dy=u.y+dir[i][1]; 63 if(dx>=0&&dx<N&&dy>=0&&dy<M&&map[dx][dy]!='#'&&!vis[dx][dy]) 64 { 65 vis[dx][dy]=true; 66 Q[Head++]=Node(dx,dy); 67 } 68 } 69 } 70 return false; 71 } 72 bool OK() 73 { 74 bool ok=true; 75 Node s; 76 int i,j; 77 for(i=0;i<N&&ok;i++) 78 { 79 for(j=0;j<M;j++) 80 { 81 if(map[i][j]=='X') 82 { 83 s.x=i;s.y=j; 84 if(!BFS(s)) 85 { 86 ok=false; 87 break; 88 } 89 } 90 } 91 } 92 return ok; 93 } 94 void Init() 95 { 96 int i,j,u; 97 memset(head,-1,sizeof(head));ecnt=0; 98 for(i=0;i<N;i++) 99 scanf("%s",map[i]); 100 scr=0;sink=1;vn=2; 101 Sum=0; 102 for(i=0;i<N;i++) 103 { 104 for(j=0;j<M;j++) 105 { 106 if(map[i][j]=='X') 107 { 108 Sum++; 109 u=i*M+j+2; 110 Insert(scr,u,1); 111 } 112 } 113 } 114 now=(M*N); 115 vn+=now; 116 } 117 int Sap(int s,int t,int n)//核心代码(模版) 118 { 119 int ans=0,aug=INF;//aug表示增广路的流量 120 int i,v,u=pre[s]=s; 121 for(i=0;i<=n;i++) 122 { 123 cur[i]=head[i]; 124 dis[i]=gap[i]=0; 125 } 126 gap[s]=n; 127 bool flag; 128 while(dis[s]<n) 129 { 130 flag=false; 131 for(int &j=cur[u];j!=-1;j=E[j].next)//一定要定义成int &j,why 132 { 133 v=E[j].v; 134 if(E[j].w>0&&dis[u]==dis[v]+1) 135 { 136 flag=true;//找到容许边 137 aug=min(aug,E[j].w); 138 pre[v]=u; 139 u=v; 140 if(u==t) 141 { 142 ans+=aug; 143 while(u!=s) 144 { 145 u=pre[u]; 146 E[cur[u]].w-=aug; 147 E[cur[u]^1].w+=aug;//注意 148 } 149 aug=INF; 150 } 151 break;//找到一条就退出 152 } 153 } 154 if(flag) continue; 155 int mindis=n; 156 for(i=head[u];i!=-1;i=E[i].next) 157 { 158 v=E[i].v; 159 if(E[i].w>0&&dis[v]<mindis) 160 { 161 mindis=dis[v]; 162 cur[u]=i; 163 } 164 } 165 if((--gap[dis[u]])==0) break; 166 gap[dis[u]=mindis+1]++; 167 u=pre[u]; 168 } 169 return ans; 170 } 171 172 bool Judge(int Ti) 173 { 174 int i,j,k,u,v,a,b,dx,dy; 175 for(i=0;i<N;i++) 176 { 177 for(j=0;j<M;j++) 178 { 179 if(map[i][j]=='#') continue; 180 u=i*M+j+1; 181 a=(Ti-1)*N*M; 182 b=a+N*M; 183 u=a+u+1; 184 for(k=0;k<5;k++) 185 { 186 dx=i+dir[k][0]; 187 dy=j+dir[k][1]; 188 if(dx>=0&&dx<N&&dy>=0&&dy<M&&map[dx][dy]!='#') 189 { 190 v=dx*M+dy+1; 191 v=b+v+1; 192 Insert(u,v,1); 193 } 194 } 195 if(map[i][j]=='@') 196 { 197 v=b+i*M+j+2; 198 Insert(v,sink,1); 199 } 200 } 201 } 202 vn+=(N*M); 203 now+=(N*M); //这个now好像没啥用 204 int t=Sap(scr,sink,vn); 205 ans+=t; 206 return ans==Sum; 207 } 208 void Solve() 209 { 210 if(Sum==0) {printf("0 ");return;} 211 if(!OK()) {printf("-1 ");return;} 212 ans=Ti=0; 213 while(true) 214 { 215 Ti++; 216 if(Judge(Ti)) break; 217 } 218 printf("%d ",Ti); 219 } 220 int main() 221 { 222 while(scanf("%d%d",&N,&M)!=EOF) 223 { 224 Init(); 225 Solve(); 226 } 227 return 0; 228 }