【HDU1733 Escape】 网络流
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1733
题目大意:有一个类似于迷宫搜索的图,‘.’代表的是无人的路,'X'代表有人的点,'#'代表此点不可通过,'@'代表门口。每个位置每一秒钟只能站一个人,每个位置到上下左右点的时间为1,问你所有人能不能出去,能出去输出所有人都出去的最小时间,否则输出-1.
解题思路: 第一次写这样的构造n层网络流的题,一开始完全没思路,纠结了良久。
先用BFS判断所有人能不能出去,不能出去直接输出-1,不用构图了。二分枚举时间,选出所有人都能出去的最小时间。因为每点每时刻只能有一个人,所有对每个位置进行一次限流操作(先拆点,再限流)。因为我们是对时间进行操作,所以我们要构造mid层层次图(mid是二分枚举的时间,每层一秒),每个位置每一秒能往上下左右四个位置走,也能停留在原位置。
这样构图,先拆点,拆成Xa点集合和Xb点集合,Xa->Xb对应点连1(限流操作),Xb向下一层的Xa对应位置以及上下左右位置连1(表示下一秒的流向),
每层Xb中的'@'都可以和超级汇点相连,只有第一层的‘X’才可以和超级源点相连。
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <queue> 4 #include <algorithm> 5 #include <cstring> 6 using namespace std; 7 8 const int mn=100024; 9 const int mm=1000000; 10 const int oo=0x3fffffff; 11 int node, st, sd, edge; 12 int reach[mm], flow[mm], next[mm]; 13 int head[mn], work[mn], que[mn], dis[mn]; 14 char map[20][20]; 15 int visit[20][20]; 16 int dir[4][2]= {1,0,-1,0,0,-1,0,1}; 17 int n, m; 18 19 struct Node 20 { 21 int x, y; 22 }; 23 24 bool BFS(int i, int j) 25 { 26 memset(visit,0,sizeof(visit)); 27 Node s, p; 28 queue<Node>q; 29 s.x=i, s.y=j; 30 q.push(s); 31 while(!q.empty()) 32 { 33 p=q.front(); 34 q.pop(); 35 for(int k=0; k<4; k++) 36 { 37 s.x=p.x+dir[k][0]; 38 s.y=p.y+dir[k][1]; 39 if(s.x>=0&&s.x<n&&s.y>=0&&s.y<m&&map[s.x][s.y]!='#'&&!visit[s.x][s.y]) 40 { 41 visit[s.x][s.y]=1; 42 if(map[s.x][s.y]=='@') return true; 43 q.push(s); 44 } 45 } 46 } 47 return false; 48 } 49 50 void init(int _node, int _st, int _sd) 51 { 52 node=_node, st=_st, sd=_sd; 53 for(int i=0; i<node; i++) 54 head[i]=-1; 55 edge=0; 56 } 57 58 inline void addedge(int u, int v, int c1, int c2) 59 { 60 reach[edge]=v, flow[edge]=c1, next[edge]=head[u],head[u]=edge++; 61 reach[edge]=u, flow[edge]=c2, next[edge]=head[v],head[v]=edge++; 62 } 63 64 bool bfs() 65 { 66 int u, v, l=0, h=0; 67 for(int i=0; i<node; i++) dis[i]=-1; 68 que[l++]=st; 69 dis[st]=0; 70 while(l!=h) 71 { 72 u=que[h++]; 73 if(h==mn) h=0; 74 for(int i=head[u]; i>=0; i=next[i]) 75 { 76 v=reach[i]; 77 if(flow[i]&&dis[v]<0) 78 { 79 dis[v]=dis[u]+1; 80 que[l++]=v; 81 if(l==mn) l=0; 82 if(v==sd) return true; 83 } 84 } 85 } 86 return false; 87 } 88 89 int dfs(int u, int exp) 90 { 91 if(u==sd) return exp; 92 for(int &i=work[u]; i>=0; i=next[i]) 93 { 94 int v=reach[i], tp; 95 if(flow[i]&&dis[v]==dis[u]+1&&(tp=dfs(v,min(flow[i],exp))>0)) 96 { 97 flow[i]-=tp; 98 flow[i^1]+=tp; 99 return tp; 100 } 101 } 102 return 0; 103 } 104 105 int Dinic() 106 { 107 int max_flow=0, flow; 108 while(bfs()) 109 { 110 for(int i=0; i<node; i++) work[i]=head[i]; 111 while(flow=dfs(st,oo)) max_flow+=flow; 112 } 113 return max_flow; 114 } 115 116 void Makegraph(int mid) 117 { 118 init(mid*2*n*m+n*m+2,0,mid*2*n*m+n*m+1); 119 for(int k=0; k<mid; k++) 120 { 121 int tp=n*m, tm=2*n*m, cnt=k*2*n*m; 122 for(int i=0; i<n; i++) 123 for(int j=0; j<m; j++) 124 { 125 if(map[i][j]!='#') 126 { 127 if(k==0&&map[i][j]=='X') addedge(st,cnt+i*m+j+1,1,0); 128 addedge(cnt+i*m+j+1,cnt+tp+i*m+j+1,1,0); 129 if(map[i][j]=='@') addedge(cnt+tp+i*m+j+1,sd,1,0); 130 else 131 { 132 addedge(cnt+tp+i*m+j+1,cnt+tm+i*m+j+1,1,0); 133 if(i!=0&&map[i-1][j]!='#') 134 addedge(cnt+tp+i*m+j+1,cnt+tm+(i-1)*m+j+1,1,0); 135 if(i!=n-1&&map[i+1][j]!='#') 136 addedge(cnt+tp+i*m+j+1,cnt+tm+(i+1)*m+j+1,1,0); 137 if(j!=0&&map[i][j-1]!='#') 138 addedge(cnt+tp+i*m+j+1,cnt+tm+i*m+j,1,0); 139 if(j!=m-1&&map[i][j+1]!='#') 140 addedge(cnt+tp+i*m+j+1,cnt+tm+i*m+j+2,1,0); 141 } 142 } 143 } 144 } 145 } 146 147 int main() 148 { 149 while(cin >> n >> m) 150 { 151 for(int i=0; i<n; i++) 152 scanf("%s",map[i]); 153 bool ok=true; 154 int num=0; 155 for(int i=0; i<n&&ok; i++) 156 for(int j=0; j<m&&ok; j++) 157 { 158 if(map[i][j]=='X') 159 { 160 num++; 161 if(!BFS(i,j)) ok=false; 162 } 163 } 164 if(!ok) puts("-1"); 165 else 166 { 167 int l=0, r=n*m, mid, ans=0; 168 while(l<=r) 169 { 170 mid=(l+r)>>1; 171 Makegraph(mid); 172 if(Dinic()<num) l=mid+1; 173 else 174 { 175 ans=mid-1; 176 r=mid-1; 177 } 178 } 179 cout << ans <<endl; 180 } 181 } 182 return 0; 183 }