首页 > 其他 > 详细

P3191 [HNOI2007]紧急疏散EVACUATE 最大流 二分

时间:2019-08-07 11:33:24      阅读:80      评论:0      收藏:0      [点我收藏+]

  

题目描述

发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是‘.‘,那么表示这是一块空地;如果是‘X‘,那么表示这是一面墙,如果是‘D‘,那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。

输入格式

输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符‘.‘、‘X‘和‘D‘,且字符间无空格。

输出格式

只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出‘impossible‘(不包括引号)。

输入输出样例

输入 #1
5 5
XXXXX
X...D
XX.XX
X..XX
XXDXX
输出 #1
3


技术分享图片
技术分享图片
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define pb push_back
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 0x3f3f3f3f
const int N=1e2+44;
const int M=1e6+54;
int d[N];
struct edge {
    int to, next, w;
} e[M << 1];
int head[M],cur[M],cnt = 1;
void add(int x, int y, int z) {
    e[++cnt] = (edge){y, head[x], z};
    head[x] = cnt;
    e[++cnt] = (edge){x, head[y], 0};
    head[y] = cnt;
}
void init()
{
    cnt=1;CLR(head,0);CLR(cur,0);
}
void ins(int x,int y,int a,int b)
{
    add(x,y,b-a);
    d[x]-=a;
    d[y]+=a;
}

int level[M];
bool bfs(int s, int t) {
    memset(level, 0, sizeof level);
    queue<int> q;
    level[s] = 1;
    q.push(s);
    while (!q.empty()) {
        int pos = q.front();q.pop();
        for (int i = head[pos]; i; i = e[i].next) {
            int nx = e[i].to;
            if (!e[i].w || level[nx]) continue;
            level[nx] = level[pos] + 1;
            q.push(nx);
        }
    }
    return level[t];
}
int dfs(int s, int t, int flow) {
    if(s==t||flow==0)return flow;

    int f,ret = 0;
    for (int &i = cur[s],v; i; i = e[i].next) {
         v = e[i].to;
        if (level[v] == level[s] + 1 && (f=dfs(v,t,min(flow,e[i].w)))>0) {
            e[i].w -= f;
            e[i ^ 1].w += f;
            flow -= f;
            ret += f;
            if(!flow)break;
        }
    }
    return ret;
}
int dinic(int s, int t) {
    int ret = 0;
    while (bfs(s, t)) memcpy(cur,head,sizeof cur),ret += dfs(s, t, inf);
    return ret;
}

int n,m,s,t,a,b,c,sum,S,T,k;
char mp[100][100],id[100][100],pos,posdoor;
int dx[]={1,0,-1,0};
int dy[]={0,-1,0,1};

vector<pair<int,int> >door,peo[400+4];

struct node
{
    int x,y,d;
}u,v;
queue<node>q;

int vis[100][100];

bool check(int mid)
{
    init();
    rep(i,1,pos)
    {
        add(s,i,1);
        for(int j=0;j<peo[i].size();j++)
        {
            if(peo[i][j].second<=mid)
            add(i,pos+2+mid*(peo[i][j].first)+peo[i][j].second,1);
        }
    }
    rep(i,1,posdoor)
    {
        rep(j,1,mid)
        {
            add( (i)*mid+j+pos+2,t,1);
            if(j!=mid)add( (i)*mid+j+pos+2,(i)*mid+j+pos+3,inf);
        }
    }
    return dinic(s,t)==pos;
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n)scanf("%s",mp[i]+1);

    rep(i,1,n)
    rep(j,1,m)
    if(mp[i][j]==D)
    door.push_back(make_pair(i,j));
    else if(mp[i][j]==.)
    id[i][j]=++pos;

    s=pos+1,t=s+1;
    posdoor=door.size();
    
    for(int i=0;i<door.size();i++)
    {
        CLR(vis,0);
        while(!q.empty())q.pop();

        u.x=door[i].first;
        u.y=door[i].second;
        u.d=0;vis[u.x][u.y]=1;
        q.push(u);int xx,yy;
        while(!q.empty())
        {
            u=q.front();q.pop();
            rep(j,0,3)
            {
                v.x=u.x+dx[j];
                v.y=u.y+dy[j];
                v.d=u.d+1;
                if(v.x>=1&&v.x<=n&&v.y>=1&&v.y<=m&&!vis[v.x][v.y]&&mp[v.x][v.y]==.)
                {
                    peo[id[v.x][v.y]].push_back(make_pair(i+1,v.d));
                    vis[v.x][v.y]=1;
                    q.push(v);
                }
            }
        }
    }
    int ans=-1,R=1000,L=1;
    while(L<=R)
    {
        int mid=(L+R)>>1;
        if(check(mid))R=mid-1,ans=mid;
        else L=mid+1;
    }
    if(ans==-1)printf("impossible\n");
    else printf("%d\n",ans);
    return 0;
}
View Code

 




P3191 [HNOI2007]紧急疏散EVACUATE 最大流 二分

原文:https://www.cnblogs.com/bxd123/p/11314152.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!