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

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 Input Sample Output
5
.....
.X...
...X.
..X..
.....
5
.X...
.X...
.X...
.XXX.
.....
0
Case 1: 6
Case 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;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值