E - Stampede!
Time Limit: 3000/1000MS (Java/Others)
Memory Limit: 131072/131072KB (Java/Others)
You have an n×n game board. Some squares contain obstacles, except the left- and right-most columns which are obstacle-free.
The left-most column is filled with your n pieces, 1 per row. Your goal is to move all your pieces to the right-most column as quickly
as possible.
In a given turn, you can move each piece N
, S
, E
, or W
one space, or leave that piece in place.
A piece cannot move onto a square containing an obstacle, nor may two pieces move to the same square on the same turn.
All pieces move simultaneously, so one may move to a location currently occupied by another piece so long as that piece itself moves
elsewhere at the same time.
Given n and the obstacles, determine the fewest number of turns needed to get all your pieces to the right-hand side of the board.
Input
Each test case starts with a positive integer n indicating the size of the game board, with n≤25 . Following this will be n lines containing
n
characters each.
If the
jth
character in the
ith
line is an X
, then there is an obstacle in board location
i,j
; otherwise this character will be a .
indicating
no obstacle.
There will never be an obstacle in the 0th or (n−1)st column and there will always be at least one obstacle-free path between these
two columns.
A line containing a single 0 will terminate input.
Output
For each test case output the minimum number of turns to move all the pieces from the left side of the board to the right side.
Sample input and output
Sample Input | Sample Output |
---|---|
5 ..... .X... ...X. ..X.. ..... 5 .X... .X... .X... .XXX. ..... 0 | Case 1: 6 Case 2: 8 |
Source
#include <cstdio>
#include <iostream>
#include <queue>
#include <vector>
#include <string.h>
using namespace std;
const int maxn=500005,maxk=5000005,inf=0x3f3f3f3f;
int num=0,current[maxn],head[maxn],r[maxn],dirx[4],diry[4];
char map[28][28];
struct Edge{
int to,flow,pre;
} edge[maxk];
void addedge(int from,int to,int flow) {
edge[num]=(Edge){to,flow,head[from]};
head[from]=num++;
edge[num]=(Edge){from,0,head[to]};
head[to]=num++;
}
bool bfs(int n) {
queue<int> q;
memset(r,-1,sizeof(r));
q.push(0);
r[0]=0;
while (!q.empty()) {
int now=q.front();
q.pop();
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (r[to]==-1&&edge[i].flow>0) {
r[to]=r[now]+1;
q.push(to);
}
}
}
return r[n]!=-1;
}
int dfs(int now,int flow,int des) {
if (now==des) return flow;
int f;
for (int i=current[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
current[now]=i;
if (edge[i].flow>0&&r[to]==r[now]+1) {
if (f=dfs(to,min(flow,edge[i].flow),des)) {
edge[i].flow-=f;
edge[i^1].flow+=f;
return f;
}
}
}
return 0;
}
int dinic(int n) {
int i,f,sum=0;
while (bfs(n)) {
memcpy(current,head,sizeof(head));
while (f=dfs(0,inf,n)) sum+=f;
}
// cout << n << ' ' << sum << endl;
return sum;
}
void buildgraph(int mid,int n) {
num=0;
memset(head,-1,sizeof(head));
int i,k=0,l,j,m;
for (i=1;i<=n;i++) {
addedge(0,(i-1)*mid*n+1,1);
addedge(i*n*mid,n*n*mid+1,1);
for (j=1;j<=n;j++) {
k++;
for (l=1;l<mid;l++) {
addedge((k-1)*mid+l,(k-1)*mid+l+1,1);
if (map[i][j-1]=='.')
for (m=0;m<4;m++) {
int nowx=i+dirx[m],nowy=j+diry[m];
if (map[nowx][nowy-1]=='.'&&nowx>0&&nowx<=n&&nowy>0&&nowy<=n) {
int u=(nowx-1)*n+nowy;
addedge((k-1)*mid+l,(u-1)*mid+l+1,1);
}
}
}
}
}
}
int solve(int n) {
int l=1,r=n*n+5,mid,ans=-1;
while (l<=r) {
mid=(l+r)/2;
buildgraph(mid,n);
if (dinic(mid*n*n+1)>=n) {
ans=mid;
r=mid-1;
} else l=mid+1;
}
return ans-1;
}
int main() {
int n,t=0,i;
scanf("%d",&n);
dirx[0]=dirx[1]=diry[2]=diry[3]=0;
dirx[2]=1;dirx[3]=-1;
diry[0]=1;diry[1]=-1;
while (n) {
t++;
for (i=1;i<=n;i++) {
scanf("%s",map[i]);
}
int ans=solve(n);
printf("Case %d: %d\n",t,ans);
scanf("%d",&n);
}
return 0;
}