P3191 [HNOI2007]紧急疏散EVACUATE

传送门

这一题很容易想到网络流

一开始傻逼地模拟整个图每一个时间的情况,显然会爆炸

发现我们只要考虑起点到门之间的距离,不用每一步只走一格

所以直接 $BFS$ 预处理距离然后二分答案,网络流判断即可

注意到了门就不能走了,所以门不能连边出去

总的来说挺傻逼的一题...但是我就是没想到...

某位不愿意透露姓名的神仙还有一种牛逼的费用流做法,代码极短$STO$

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=2e5+7,M=5e6+7,INF=1e9+7,xx[4]={0,1,0,-1},yy[4]={1,0,-1,0};
int fir[N],from[M<<1],to[M<<1],val[M<<1],cntt=1;
inline void add(int a,int b,int c)
{
    from[++cntt]=fir[a]; fir[a]=cntt;
    to[cntt]=b; val[cntt]=c;
    from[++cntt]=fir[b]; fir[b]=cntt;
    to[cntt]=a; val[cntt]=0;
}
int n,m,tot,id[507][27][27],sum;
int dep[N],S,T;
queue <int> Q;
bool BFS()
{
    for(int i=0;i<=tot;i++) dep[i]=0;
    Q.push(S); dep[S]=1;
    while(!Q.empty())
    {
        int x=Q.front(); Q.pop();
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(dep[v]||(!val[i])) continue;
            dep[v]=dep[x]+1; Q.push(v);
        }
    }
    return dep[T]>0;
}
int DFS(int x,int mxfl)
{
    if(x==T||!mxfl) return mxfl;
    int fl=0,res;
    for(int i=fir[x];i;i=from[i])
    {
        int &v=to[i]; if(dep[v]!=dep[x]+1||!val[i]) continue;
        if( res=DFS(v,min(mxfl,val[i])) )
        {
            mxfl-=res; fl+=res;
            val[i]-=res; val[i^1]+=res;
            if(!mxfl) break;
        }
    }
    return fl;
}
char mp[233][233];
int dis[27][27][27][27];
struct dat{
    int x,y;
    dat (int a=0,int b=0) { x=a,y=b; }
};
queue <dat> q;
void pre()
{
    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(mp[i][j]!='.') continue;
            q.push(dat(i,j)); dis[i][j][i][j]=0;
            while(!q.empty())
            {
                dat u=q.front(); q.pop();
                for(int k=0;k<4;k++)
                {
                    int tx=u.x+xx[k],ty=u.y+yy[k];
                    if(tx<1||tx>n||ty<1||ty>m||mp[tx][ty]=='X'||dis[i][j][tx][ty]<M) continue;
                    dis[i][j][tx][ty]=dis[i][j][u.x][u.y]+1;
                    if(mp[tx][ty]!='D') q.push(dat(tx,ty));
                }
            }
        }
}
bool check(int mid)
{
    for(int i=0;i<=tot;i++) fir[i]=0; tot=1; S=0,T=1; cntt=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(mp[i][j]=='.') id[0][i][j]=++tot,add(S,tot,1);
    for(int t=1;t<=mid;t++)
        for(int k=1;k<=n;k++)
            for(int l=1;l<=m;l++)
                if(mp[k][l]=='D') id[t][k][l]=++tot,add(tot,T,1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(mp[i][j]!='.') continue;
            for(int t=1;t<=mid;t++)
                for(int k=1;k<=n;k++)
                    for(int l=1;l<=m;l++)
                        if(mp[k][l]=='D'&&dis[i][j][k][l]<=t) add(id[0][i][j],id[t][k][l],INF);
        }
    int now=0;
    while(BFS())
    {
        now+=DFS(S,INF);
        if(now>=sum) break;
    }
    for(int t=0;t<=mid;t++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) id[t][i][j]=0;
    return now>=sum;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) sum+=(mp[i][j]=='.');
    pre();
    int L=0,R=n*m,mid,ans=M;
    while(L<=R)
    {
        mid=L+R>>1;
        if(check(mid)) R=mid-1,ans=mid;
        else L=mid+1;
    }
    if(ans==M) printf("impossible\n");
    else printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-08-20 09:24  LLTYYC  阅读(188)  评论(0编辑  收藏  举报