最大匹配+二分答案POJ 3057 Evacuation
Posted midoria7
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最大匹配+二分答案POJ 3057 Evacuation相关的知识,希望对你有一定的参考价值。
题目大意
POJ链接
有一个(X×Y)的房间,X
代表墙壁,D
是门,.
代表人。这个房间着火了,人要跑出去,但是每一个时间点只有一个人可以从门出去。
问最后一个人逃出去的最短时间,如果不能逃出去,输出impossible
。
输入格式
第一行一个整数(T),表示有T组数据。
每组数据,第一行两个数字(Y,X),接下来有一个(X×Y)的图。
输出格式
(T)行答案,表示最后一个人逃出去的最短时间,如果不能逃出去,输出impossible
。
数据范围
(3le Yle Xle 12)
样例输入
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
样例输出
3
21
impossible
思路
找到一个人之后,设他能到达某扇门的时间为(t),那么可以把从(t)到最大时间每一秒的这扇门和这个人建边,因为只要能到达,之后任何一秒都可以选择出去。从时间小的门的点开始匹配。看一下多长时间人和们都能匹配上。
查询人到门的距离用BFS,而最后求答案要用二分。
代码
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int maxn=1e6+10;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
int x,y;
char g[20][20];
int match[maxn];
struct Edge{
int to,nxt,val;
}edge[maxn];
struct Node{
int x,y,t;
Node(){}
Node(int a,int b,int c){
x=a;y=b;t=c;
}
};
int head[maxn],tot;
void add(int a,int b,int w){
edge[++tot].to=b;
edge[tot].val=w;
edge[tot].nxt=head[a];
head[a]=tot;
}
queue<Node> q;
int cal1(int a,int b){
return y*(a-1)+b;//两个数映射成一个数
}
int cal2(int a,int b,int t){
return (cal1(a,b)-1)*100+t;
}
void add2(int a,int b,int xx,int yy,int t){
for(int i=t;i<=100;i++)
add(cal1(a,b),cal2(xx,yy,i),i);//把这个人和之后分成的多个门建边
}
bool vis[20][20];
void bfs(int a,int b){
memset(vis,0,sizeof(vis));
vis[a][b]=true;
q.push(Node(a,b,0));
while(!q.empty()){
Node now=q.front();q.pop();
for(int i=0;i<4;i++){
int xx=now.x+dx[i];
int yy=now.y+dy[i];
if(xx>=1&&xx<=x&&yy>=1&&yy<=y&&!vis[xx][yy]&&g[xx][yy]==‘.‘){
vis[xx][yy]=true;
q.push(Node(xx,yy,now.t+1));
}
if(xx>=1&&xx<=x&&yy>=1&&yy<=y&&!vis[xx][yy]&g[xx][yy]==‘D‘){
vis[xx][yy]=true;
add2(a,b,xx,yy,now.t+1);//找到了门
}
}
}
}
bool vis2[maxn];
bool dfs(int x,int t){
for(int i=head[x];i;i=edge[i].nxt){
if(vis2[edge[i].to]||edge[i].val>t)continue;
vis2[edge[i].to]=true;
if(match[edge[i].to]==0||dfs(match[edge[i].to],t)){
match[edge[i].to]=x;
return true;
}
}
return false;
}
bool judge(int t){
memset(match,0,sizeof(match));
for(int i=1;i<=x;i++)
for(int j=1;j<=y;j++)
if(g[i][j]==‘.‘){
memset(vis2,0,sizeof(vis2));
if(!dfs(cal1(i,j),t))return false;
}
return true;
}
void arrclear(){
memset(head,0,sizeof(head));
}
int main(){
freopen("123.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
arrclear();
scanf("%d%d",&x,&y);
tot=0;
for(int i=1;i<=x;i++)
for(int j=1;j<=y;j++)
scanf(" %c",&g[i][j]);
for(int i=1;i<=x;i++)
for(int j=1;j<=y;j++)
if(g[i][j]==‘.‘)bfs(i,j);//找到人bfs
int l=0,r=100;//卡的贼严,还是开小点
while(l<=r){//二分答案
int mid=(l+r)/2;
if(judge(mid))r=mid-1;
else l=mid+1;
}
if(l==100+1)printf("impossible
");
else printf("%d
",l);
}
return 0;
}
以上是关于最大匹配+二分答案POJ 3057 Evacuation的主要内容,如果未能解决你的问题,请参考以下文章