Case 2: 8
开始假设这题也是类似推箱子的问题是无障碍移动,先bfs求最短路,然后二分用最大匹配判合法,wa了。然后找了组数据反驳了这个假设。立马想到了根据时间拆点建图,二分最大时间limit,每个点就拆成了limit+1个,源点向左边一列时间为0的点连边,右边一列时间为limit的点向汇点连边,注意每条边的容量都是1,然后跑最大流判合法性。
#include<cstdio> #include<map> #include<queue> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<list> #include<set> #include<cmath> using namespace std; const int maxn = 1e3 + 5; const int INF = 1e9; const double eps = 1e-6; typedef unsigned long long ULL; typedef long long LL; typedef pair<int, int> P; #define fi first #define se second struct Edge{ int from, to, cap, flow; }; struct Dinic{ int n, m, s, t; vector<Edge> edges; vector<int> G[maxn*maxn]; bool vis[maxn*maxn]; int d[maxn*maxn]; int cur[maxn*maxn]; void AddEdge(int from, int to, int cap){ edges.push_back((Edge){from, to, cap, 0}); edges.push_back((Edge){to, from, 0, 0}); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } void init(int n){ for(int i = 0;i < n;i++) G[i].clear(); edges.clear(); } bool BFS(){ memset(vis, 0, sizeof vis); queue<int> Q; Q.push(s); d[s] = 0; vis[s] = 1; while(!Q.empty()){ int x = Q.front();Q.pop(); for(int i = 0;i < G[x].size();i++){ Edge& e = edges[G[x][i]]; if(!vis[e.to] && e.cap > e.flow){ vis[e.to] = 1; d[e.to] = d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x, int a){ if(x == t || a == 0) return a; int flow = 0, f; for(int& i = cur[x];i < G[x].size();i++){ Edge& e = edges[G[x][i]]; if(d[x]+1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0){ e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t){ this -> s = s; this -> t = t; int flow = 0; while(BFS()){ memset(cur, 0, sizeof cur); flow += DFS(s, INF); } return flow; } }; Dinic solver; char maze[maxn][maxn]; int n; int id(int x, int y, int ceng){ return x*n+y+1+ceng*n*n; } const int cx[] = {-1, 0, 1, 0}; const int cy[] = {0, 1, 0, -1}; bool test(int limit){ solver.init(n*n*(limit+1)+5); int source = 0, sink = n*n*(limit+1)+1; for(int i = 0;i < n;i++){ solver.AddEdge(source, id(i, 0, 0), 1); solver.AddEdge(id(i, n-1, limit), sink, 1); } for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ if(maze[i][j]=='.'){ for(int k = 0;k < limit;k++){ solver.AddEdge(id(i, j, k), id(i, j, k+1), 1); for(int dir = 0;dir < 4;dir++){ int tx = i+cx[dir]; int ty = j+cy[dir]; if(tx>=0 && tx<n && ty>=0 && ty<n && maze[tx][ty]=='.'){ solver.AddEdge(id(i, j, k), id(tx, ty, k+1), 1); } } } } } } if(solver.Maxflow(source, sink)==n) return true; return false; } int main(){ int kase = 0; while(cin >> n){ if(n == 0) break; kase++; for(int i = 0;i < n;i++) cin >> maze[i]; int l = 0, r = n*n+10, ans; while(l <= r){ int mid = (l+r)/2; if(test(mid)){ ans = mid; r = mid-1; } else l = mid+1; } printf("Case %d: %d\n", kase, ans); } return 0; }