[POJ3057] Evacuation
题目
解说
这个看着像\(BFS\)一样的东西居然还是个二分图……(当然也要用到\(BFS\))
先\(BFS\)处理处每个人距离每一扇门的最短距离,并分别保存在单独一扇门对应的集合中;
若一个人能到达一扇门,则将该人与之后各时刻该门的建边;
求二分图的最大匹配,看是否能将所有人匹配完;从小时刻向大时刻枚举门,则为最优解。
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 12+3;
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(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((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;
}
幸甚至哉,歌以咏志。
签名:
我将轻轻叹息,叙述这一切,
许多许多年以后:
林子里有两条路,我——
选择了行人稀少的那一条,
它改变了我的一生。