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;
}