POJ 3057 bfs +二分图匹配

题意

传送门 POJ 3057

题解

基本按照白书思路写的。考虑到不同时间不同的门只有一个人可以逃生,则每个时间和门的二元组,都确定一个对应的能逃生的人的集合。一个人否在某个时间点从某个门逃生,可以根据 bfs 求得的最短路确定 。每一个二元组作为一个顶点向在该时间点能逃生的人的集合连边,按时间顺序新增二元组顶点寻找增广路增广即可,满足匹配数等于人数的最小时间即答案。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#define min(a,b)    (((a) < (b)) ? (a) : (b))
#define max(a,b)    (((a) > (b)) ? (a) : (b))
#define abs(x)    ((x) < 0 ? -(x) : (x))
#define INF 0x3f3f3f3f
#define delta 0.85
#define eps 1e-5
#define PI 3.14159265358979323846
#define MAX_X 12
#define MAX_Y 12
using namespace std;
const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};
int X, Y;
char field[MAX_X][MAX_Y + 1];
int dist[MAX_X][MAX_Y][MAX_X][MAX_Y];
vector<int> pX, pY, dX, dY;

void bfs(int x, int y, int d[MAX_X][MAX_Y]){
	d[x][y] = 0;
	queue<int> qx, qy;
	qx.push(x);
	qy.push(y);
	while(!qx.empty()){
		int x = qx.front(); qx.pop();
		int y = qy.front(); qy.pop();
		for(int i = 0; i < 4; i++){
			int nx = x + dx[i], ny = y + dy[i];
			if(nx >= 0 && nx < X && ny >= 0 && ny < Y && field[nx][ny] == '.' && d[nx][ny] == INF){
				d[nx][ny] = d[x][y] + 1;
				qx.push(nx);
				qy.push(ny);
			}
		}
	}
}

const int MAX_V = MAX_X * MAX_Y * 2 * (MAX_X + MAX_Y) + MAX_X * MAX_Y;
int V;
vector<int> G[MAX_V];
int match[MAX_V];
bool used[MAX_V];

void add_edge(int u, int v){
	G[u].push_back(v);
	G[v].push_back(u);
}

bool dfs(int v){
	used[v] = 1;
	for(int i = 0; i < G[v].size(); i++){
		int u = G[v][i], w = match[u];
		if(w == -1 || (!used[w] && dfs(w))){
			match[u] = v;
			match[v] = u;
			return true;
		}
	}
	return false;
}

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		pX.clear(); pY.clear();
		dX.clear(); dY.clear();
		memset(dist, 0x3f, sizeof(dist));
		scanf("%d%d", &X, &Y);
		for(int i = 0; i < X; i++) scanf(" %s", field + i);
		// 计算人到各个门的最短距离
		for(int i = 0; i < X; i++){
			for(int j = 0; j < Y; j++){
				if(field[i][j] == 'D'){
					bfs(i, j, dist[i][j]);
					dX.push_back(i);
					dY.push_back(j);
				}
				else if(field[i][j] == '.'){
					pX.push_back(i);
					pY.push_back(j);
				}
			}
		}
		// 门 i 在时间 k 的索引 : (k - 1) * d + i
		// 人 j 的索引: n * d + j
		int p = pX.size(), d = dX.size(), n = X * Y, V = d * n + p;
		for(int v = 0; v < V; v++) G[v].clear();
		for(int i = 0; i < d; i++){
			for(int j = 0; j < p; j++){
				int t;
				if((t = dist[dX[i]][dY[i]][pX[j]][pY[j]]) != INF){
					for(int k = t ; k <= n; k++){
						add_edge((k - 1) * d + i, n * d + j);
					}
				}
			}
		}
		// 按照时间递增顺序增广
		bool flag = 0;
		int cnt = 0, sz = n * d;
		memset(match, -1, sizeof(match));
		for(int v = 0; v < sz; v++){
			memset(used, 0, sizeof(used));
			if(dfs(v)){
				++cnt;
				if(cnt == p){
					flag = 1;
					printf("%d\n", v / d + 1);
					break;
				}
			}
		}
		if(!flag) printf("impossible\n");
	}
	return 0;
}
发布了91 篇原创文章 · 获赞 1 · 访问量 1587

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/105361274