Evacuation POJ - 3057

Evacuation

 POJ - 3057 

Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time, it may take a while for everyone to escape. 

You are given the floorplan of a room and must find out how much time it will take for everyone to get out. Rooms consist of obstacles and walls, which are represented on the map by an 'X', empty squares, represented by a '.' and exit doors, which are represented by a 'D'. The boundary of the room consists only of doors and walls, and there are no doors inside the room. The interior of the room contains at least one empty square. 

Initially, there is one person on every empty square in the room and these persons should move to a door to exit. They can move one square per second to the North, South, East or West. While evacuating, multiple persons can be on a single square. The doors are narrow, however, and only one person can leave through a door per second. 

What is the minimal time necessary to evacuate everybody? A person is evacuated at the moment he or she enters a door square.

Input

The first line of the input contains a single number: the number of test cases to follow. Each test case has the following format: 
One line with two integers Y and X, separated by a single space, satisfying 3 <= Y, X <= 12: the size of the room 
Y lines with X characters, each character being either 'X', '.', or 'D': a valid description of a room

Output

For every test case in the input, the output should contain a single line with the minimal evacuation time in seconds, if evacuation is possible, or "impossible", if it is not. 

Sample Input

3
5 5
XXDXX
X...X
D...X
X...D
XXXXX
5 12
XXXXXXXXXXXX
X..........D
X.XXXXXXXXXX
X..........X
XXXXXXXXXXXX
5 5
XDXXX
X.X.D
XX.XX
D.X.X
XXXDX

Sample Output

3
21
impossible

题目大意:

对于给定一个图,图中包含 ‘D’表示门,‘X’表示墙,‘.’表示空白处。

要求设定每一个‘.’处有一个人,然后每一秒钟内,智能有一个人通过这个门,求最终所有人都逃出门的最短时间

将时间和门作为一个二元组, 就有时间和门的二元组和人之间的图的关系,求对应的匹配数,如果匹配数满足人的数量,则对应的时间就是即为所求。

代码,使用最大流算法结合二分查找(超时):

#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXN  = 15;
 
char map[MAXN][MAXN];
int dist[MAXN][MAXN][MAXN][MAXN];

//s->

struct edge{
	int to,cap,rev;
	edge(int to,int cap,int rev):to(to),cap(cap),rev(rev){};
};
 
const int INF = 0x3f3f3f3f;
const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,1,0,-1};
int Y,X;
 
vector<edge> G[MAXN*MAXN*MAXN*MAXN+MAXN*MAXN];
bool used[MAXN*MAXN*MAXN*MAXN+MAXN*MAXN];
 
vector<int> qX,qY;
vector<int> dX,dY;
vector<int> point_s,point_t;
void add_edge(int from,int to,int cap){
	G[from].push_back(edge(to,cap,G[to].size()));
	G[to].push_back(edge(from,0,G[from].size()-1));
}
 
void bfs(int x, int y,int d[MAXN][MAXN]){
	d[y][x] = 0;
	queue<int> Qx;
	queue<int> Qy;
	
//	printf("bfs y :%d  x :%d \n",y,x);
	Qx.push(x);
	Qy.push(y);
	
	while(!Qx.empty()){
		int x1 = Qx.front(); Qx.pop();
		int y1 = Qy.front(); Qy.pop();
		for(int i=0;i<4;i++){
			int x2 = x1+dx[i];
			int y2 = y1+dy[i];
			
			if(0<=x2 && x2<X && 0<=y2 && y2<Y && 
			d[y2][x2]<0 && map[y2][x2] == '.'){
				d[y2][x2] = d[y1][x1] + 1;
				Qx.push(x2);
				Qy.push(y2);
//				printf(" - bfs y :%d  x :%d ==>y2:%d  x2:%d  dist:%d \n",y,x,y2,x2,d[y2][x2] );
			}
		}
	}
}
 
int dfs(int from,int to,int f){
//	printf("-- dfs from :%d  to :%d f:%d \n",from,to,f );
 
	if(from==to) return f;
	used[from] = true;
	
	for(int i=0;i<G[from].size();i++){
		edge &e = G[from][i];
		if(e.cap>0 && !used[e.to]){
			int d = dfs(e.to,to,min(f,e.cap));
			if(d>0){
				e.cap-=d;
				G[e.to][e.rev].cap+=d;
				return d;
			}
		}
	}
//	printf("-- dfs from :%d  to :%d f:%d \n",from,to,f );
	return 0;
}
 
int solve(int s,int t){
	int max_flow = 0;
	
	while(true){
		memset(used,0,sizeof(used));
		int d = dfs(s,t,INF);
		if(d==0) return max_flow;
		max_flow += d;
	}
	return  max_flow;
}
 
 
bool C(int t){
	int pNum = qX.size();
	int dNum = dX.size();
	
	int V = t*dNum + pNum;
	

	point_s.clear();
	point_t.clear();
	for(int i=0;i<V+2;i++) G[i].clear();
	for(int i=0;i<dNum;i++)
		for(int j=0;j<pNum;j++){
			if(dist[dY[i]][dX[i]][qY[j]][qX[j]]>=0){
				for(int k=dist[dY[i]][dX[i]][qY[j]][qX[j]];k<=t;k++){
					add_edge((k-1)*dNum+i,t*dNum+j,1);
//					printf("add_edge from:%d to : %d",)
					point_s.push_back((k-1)*dNum+i);
					point_t.push_back(t*dNum+j);
				}
			}
		}
	//存进去的目的是防止重复添加边,去掉重复的顶点 
	sort(point_s.begin(),point_s.end());
	sort(point_t.begin(),point_t.end());
	point_s.erase(unique(point_s.begin(),point_s.end()),point_s.end());
	point_t.erase(unique(point_t.begin(),point_t.end()),point_t.end());
	int s_ = V;
	int t_ = s_+1;

	for(int i=0;i<point_s.size();i++) 
		add_edge(s_,point_s[i],1);
	for(int j=0;j<point_t.size();j++) add_edge(point_t[j],t_,1);

	return solve(s_,t_) == pNum;
}
 
 
int main(){
	int T;
	scanf("%d",&T);
 
	while(T--){
		scanf("%d%d",&Y,&X);
		
		for(int i=0;i<Y;i++){
			getchar();
			for(int j=0;j<X;j++){
				scanf("%c",&map[i][j]); 
			}
		}
		
		memset(dist,-1,sizeof(dist));
		dX.clear();dY.clear();
		qX.clear();qY.clear(); 
		
		for(int i=0;i<Y;i++){
			for(int j=0;j<X;j++){
				if(map[i][j]=='D'){
					bfs(j,i,dist[i][j]);
					dX.push_back(j);
					dY.push_back(i);
//					printf("dx : %d  dy :%d\n",j,i); 
					
				}else if(map[i][j]=='.'){
					qX.push_back(j);
					qY.push_back(i);
//					printf("px : %d  py :%d\n",j,i); 
				}
			}
		}
		
		int n = X*Y;
		int lb = -1; int ub = n+1;
		
		while(ub-lb>1){
			int mid = (ub+lb)/2;
			if(C(mid)) ub = mid;
			else lb = mid;
		}
		
		if(ub>n) printf("impossible\n");
		else printf("%d\n",ub);
	
	}
	return 0;
} 

直接基于最大时间点的二分图进行计算(AC):

#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXN  = 15;
 
char map[MAXN][MAXN];
int dist[MAXN][MAXN][MAXN][MAXN];

const int INF = 0x3f3f3f3f;
const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,1,0,-1};
int Y,X;
 
vector<int> G[MAXN*MAXN*MAXN*MAXN+MAXN*MAXN];
bool used[MAXN*MAXN*MAXN*MAXN+MAXN*MAXN];
int match[MAXN*MAXN*MAXN*MAXN+MAXN*MAXN]; 
vector<int> qX,qY;
vector<int> dX,dY;

void add_edge(int from,int to){
	G[from].push_back(to);
	G[to].push_back(from);
}
 
 
 
void bfs(int x, int y,int d[MAXN][MAXN]){
	d[y][x] = 0;
	queue<int> Qx;
	queue<int> Qy;
	
	Qx.push(x);
	Qy.push(y);
	
	while(!Qx.empty()){
		int x1 = Qx.front(); Qx.pop();
		int y1 = Qy.front(); Qy.pop();
		for(int i=0;i<4;i++){
			int x2 = x1+dx[i];
			int y2 = y1+dy[i];
			
			if(0<=x2 && x2<X && 0<=y2 && y2<Y && 
			d[y2][x2]<0 && map[y2][x2] == '.'){
				d[y2][x2] = d[y1][x1] + 1;
				Qx.push(x2);
				Qy.push(y2);
			}
		}
	}
}
 
bool dfs(int from){
	used[from] = true;
	
	for(int i=0;i<G[from].size();i++){
		int u = G[from][i];
		int w = match[u];
		if(w<0 || !used[w] && dfs(w)){
			match[u] = from;
			match[from] = u;
			return true;
		}
	}
	return false;
}
 
int solve(int V,int pNum){
	int res = 0;
	
	if(pNum == 0){
		printf("0\n");
		return 0;
	}
	
	memset(match,-1,sizeof(match));
	
	for(int i=0;i<V;i++){
		if(match[i]<0){
			memset(used,0,sizeof(used));
			if(dfs(i)){
				res++;
			}
			if(pNum == res) {
				printf("%d\n",i/dX.size() +1);return 0 ;
			} 
		}
	}
	
	printf("impossible\n");
	return  0;
}
 
 
bool C(int t){
	int pNum = qX.size();
	int dNum = dX.size();
	
	int V = t*dNum + pNum;

	for(int i=0;i<V;i++) G[i].clear();
	for(int i=0;i<dNum;i++)
		for(int j=0;j<pNum;j++){
			if(dist[dY[i]][dX[i]][qY[j]][qX[j]]>=0){
				for(int k=dist[dY[i]][dX[i]][qY[j]][qX[j]];k<=t;k++){
					add_edge((k-1)*dNum+i,t*dNum+j);
				}
			}
		}
			
	solve(V,pNum);

	return 0;
}
 
 
int main(){
	int T;
	scanf("%d",&T);
 
	while(T--){
		scanf("%d%d",&Y,&X);
		
		for(int i=0;i<Y;i++){
			getchar();
			for(int j=0;j<X;j++){
				scanf("%c",&map[i][j]);
			}
		}
		
		memset(dist,-1,sizeof(dist));
		dX.clear();dY.clear();
		qX.clear();qY.clear();
		
		for(int i=0;i<Y;i++){
			for(int j=0;j<X;j++){
				if(map[i][j]=='D'){
					bfs(j,i,dist[i][j]);
					dX.push_back(j);
					dY.push_back(i);
					
				}else if(map[i][j]=='.'){
					qX.push_back(j);
					qY.push_back(i);
				}
			}
		}
		
		int n = X*Y;
		int num = C(n);
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/Willen_/article/details/87694483