UVA Live 6557 Stampede! (uestc oj 871) 最大流+二分

来源:互联网 发布:我的世界ae2教程知乎 编辑:程序博客网 时间:2024/05/17 01:09

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 NSE, 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 n25. 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 (n1)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 InputSample Output
5......X......X...X.......5.X....X....X....XXX......0
Case 1: 6Case 2: 8

Source

2013 East Central Regional Contest

给你一个地图,.表示可以走,X表示不能走,左边n个点开始时有n个人,问从左边n个点走到右边n个点最短时间是多少。
每个点任意时刻仅可容纳一个人。

网络流。
左边n个点到右边n个点,显然是一个多源点多汇点题目。题目要求每个点任意时刻只能有一个人,那么我们建图时可以二分时间t,
将一个点拆成t+1个点,分别表示时刻0,1,...t的该点。之后,根据所给地图建图,跑最大流就好了。
时限应该是20s,坑爹的oj...害的我跑到codeforces gym去测这题

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