P3191 [HNOI2007] 紧急疏散EVACUATE 题解
题目描述
题目解法
看到数据范围:网络流
看到求时间:二分或分层
再看到给出的数据:BFS
所以我选择网络流+分层+BFS
建图
-
首先每个空地
都有一个人,所以从源点 连一条流量为 的边到 。 -
然后对每个门
进行 BFS,若点 到 号门的距离为 ,则说明从 到门 最短耗时 。由于每个门每个时刻只能撤离 个人,所以我们对门进行拆点,将门 拆成 个点,对于 , 就代表第 时刻的门。所以从 连一条流量为 的边到 , 代表第 号门的第 时刻的状态。 -
从
连一条流量为 的边到 ,该时刻没有撤离的人,可以向下一时刻 转移。
在 BFS 过程中判断是否有解。
本蒟蒻因为 BFS 写错 MLE on #2
分层
鉴于本题中
在每次连边完成后在残量网络上跑最大流,如果最大流的和等于总人数,那么就输出
因为每次跑最大流不需要重新建图,只需要连边,效率并不差。
Code
#include<bits/stdc++.h> using namespace std; template<typename Tp, size_t sizn, size_t sizm> struct netflow { int cnt=1, s=sizn-3, t=sizn-2; Tp val[sizm<<1], dis[sizn]; void link(int u, int v, Tp w) { to [++cnt]=v; val [cnt]=w; nxt[ cnt ]=head[u]; head[ u ]=cnt; to [++cnt]=u; val [cnt]=0; nxt[ cnt ]=head[v]; head[ v ]=cnt; } private: int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1]; const Tp inf=((Tp)INFINITY)>>1; int bfs() { for(int i=1;i<sizn;i++) dis[i]=inf; queue<int> q; q.push(s); dis[s]=0; now[s]=head[s]; while (!q.empty()) { int idx=q.front(); q.pop(); for(int i=head[idx];i;i=nxt[i]) { int arr=to[i]; if(val[i]>0&&dis[arr]==inf) { q.push(arr); now[arr]=head[arr]; dis[arr]=dis [idx]+1; if(arr==t) return 1; } } } return 0; } Tp dfs(int idx, Tp sum) { if(idx==t) return sum; Tp k, res=0; for(int i=now[idx];i&∑i=nxt[i]) { now[idx]=i; int arr=to[i]; if(val[i]>0&&(dis[arr]==dis[idx]+1)) { k=dfs(arr, min(sum, val[i])); if(k==0) dis[arr]=inf; val[i]-=k; res+=k; val[i^1]+=k; sum-=k; } } return res; } public: Tp maxflow() { Tp ans=0; while (bfs()) ans+=dfs(s, inf); return ans; } }; netflow<int, 50004, 1000006> nf; struct st { int d, y, x; st(int x, int y, int d=0): x(x), y(y), d(d) {}; }; char mp[25][25]; int vis[25][25], dis[25][25]; int dx[]={1, -1, 0, 0}; int dy[]={0, 0, 1, -1}; int n, m; #define chk(x, y) ((x)&&(y)&&((x)<=n)&&((y)<=m)) #define pos(x, y) (((x)-1)*m+(y)) queue<st> q; int tot=0, cdd; void bfs(int x, int y, int cc) { q.emplace(x, y); memset(vis, 0, sizeof vis); while(!q.empty()) { auto [d, y, x]=q.front(); q.pop(); for(int i=0;i<4;i++) { int nx=x+dx[i]; int ny=y+dy[i]; if(!chk(nx, ny)||mp[nx][ny]!='.'||vis[nx][ny]) continue; dis[nx][ny]=vis[nx][ny]=1; nf.link(pos(nx, ny), n*m+cdd*d+cc, 1); q.emplace(nx, ny, d+1); } } } char gc() { char c=getchar(); while(c!='X'&&c!='.'&&c!='D') c=getchar(); return c; } vector<pair<int, int> > vp; int main() { int cnt=0; cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { mp[i][j]=gc(); if(mp[i][j]=='D') vp.emplace_back(i, j), cdd++; if(mp[i][j]=='.') nf.link(nf.s, pos(i, j), 1), cnt++; } int tmp=0; for(auto [x, y]:vp) bfs(x, y, ++tmp); tmp=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) tmp+=dis[i][j]; if(tmp!=cnt) return cout<<"impossible", 0; int flow=0; for(int i=1;;i++) { for(int j=1;j<=cdd;j++) nf.link(n*m+(i-1)*cdd+j, nf.t, 1); for(int j=1;j<=cdd;j++) nf.link(n*m+(i-1)*cdd+j, n*m+i*cdd+j, 0x3f3f3f3f); flow+=nf.maxflow(); if(flow==cnt) return cout<<i, 0; } }
本文作者:Jimmy-LEEE
本文链接:https://www.cnblogs.com/redacted-area/p/18379532
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步