最大流——BZOJ1189/Luogu3191 [HNOI2007]紧急疏散evacuate

来源:互联网 发布:免费同声翻译软件 编辑:程序博客网 时间:2024/04/29 10:08

题面:BZOJ1189 Luogu3191
首先我们预处理出每个空地到每扇门的最短时间
然后我们二分时间t,然后把每扇门拆成t个点
接下来建图:超级原点->每块空地(流1),每扇门的每一个时刻->超级汇点(流1)
然后对于每块空地,枚举能够在t时间内到达的门,连上边(流1,空地->门(对应的最短时间那个时刻点))
然后等待的问题只要每扇门的某一时刻点向下一时刻点连上就行了(流INF)
然后跑最大流判断是否满流(流为所有人)就好了

#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <iostream>#include <ctime>#include <map>#include <queue>#include <cstdlib>#include <string>#include <climits>#include <set>#include <vector>using namespace std;struct ppap{int x,y;};const int dx[5]={0,1,-1,0,0};const int dy[5]={0,0,0,1,-1};bool vis[401][401];int d[201][201][201],n,m,s,t,mn=0,rp[401][401];char S[401];int nedge=-1,p[500001],c[500001],nex[500001],head[500001];int dist[500001],cnt=0,cur[500001];inline void addedge(int x,int y,int z){    p[++nedge]=y;c[nedge]=z;nex[nedge]=head[x];head[x]=nedge;}inline bool bfs(int s,int t){    queue<int>q;q.push(s);    memset(dist,-1,sizeof dist);dist[s]=1;    while(!q.empty()){        int now=q.front();q.pop();        for(int k=head[now];k>-1;k=nex[k])if(c[k]&&dist[p[k]]==-1){            dist[p[k]]=dist[now]+1;q.push(p[k]);        }    }    return dist[t]>-1;}inline int dfs(int x,int low){    if(x==t)return low;    int a,used=0;    for(int k=cur[x];k>-1;k=nex[k])if(c[k]&&dist[p[k]]==dist[x]+1){        a=dfs(p[k],min(c[k],low-used));        if(a)c[k]-=a,c[k^1]+=a,used+=a;        if(c[k])cur[x]=k;        if(used==low)break;    }    if(!used)dist[x]=-1;    return used;}inline int dinic(){    int flow=0;    while(bfs(s,t)){        for(int i=s;i<=t;i++)cur[i]=head[i];        flow+=dfs(s,1e9);    }    return flow;}inline void spfa(int co,int x,int y){    queue<ppap>q;q.push((ppap){x,y});    memset(vis,0,sizeof vis);vis[x][y]=1;d[co][x][y]=0;    while(!q.empty()){        ppap now=q.front();q.pop();        for(int i=1;i<5;i++){            int xx=now.x+dx[i],yy=now.y+dy[i];            if(xx<1||yy<1||xx>n||yy>m||rp[xx][yy]!=0)continue;            if(d[co][xx][yy]>d[co][now.x][now.y]+1){                d[co][xx][yy]=d[co][now.x][now.y]+1;                if(!vis[xx][yy])vis[xx][yy]=1,q.push((ppap){xx,yy});            }        }vis[now.x][now.y]=0;    }}inline bool check(int x){    s=0;t=n*m+mn*x+1;    nedge=-1;memset(nex,-1,sizeof nex);memset(head,-1,sizeof head);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)if(rp[i][j]==0)addedge(s,(i-1)*m+j,1),addedge((i-1)*m+j,s,0);    for(int i=1;i<=mn;i++)        for(int j=1;j<=x;j++)addedge(n*m+(i-1)*x+j,t,1),addedge(t,n*m+(i-1)*x+j,0);    for(int i=1;i<=mn;i++)        for(int j=1;j<x;j++)addedge(n*m+(i-1)*x+j,n*m+(i-1)*x+j+1,1e9),addedge(n*m+(i-1)*x+j+1,n*m+(i-1)*x+j,0);    for(int k=1;k<=mn;k++)        for(int i=1;i<=n;i++)            for(int j=1;j<=m;j++)if(rp[i][j]==0&&d[k][i][j]<=x)addedge((i-1)*m+j,n*m+(k-1)*x+d[k][i][j],1),addedge(n*m+(k-1)*x+d[k][i][j],(i-1)*m+j,0);    return dinic()==cnt;}int main(){    memset(rp,-1,sizeof rp);    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        scanf("%s",S+1);        for(int j=1;j<=m;j++)if(S[j]=='.')rp[i][j]=0,cnt++;        else if(S[j]=='D')rp[i][j]=++mn;    }    for(int i=1;i<=mn;i++)for(int j=1;j<=n;j++)for(int k=1;k<=m;k++)d[i][j][k]=1e9;    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(rp[i][j]>0)spfa(rp[i][j],i,j);    int l=0,r=1000,ans=1e9;    while(l<=r){        int mid=l+r>>1;        if(check(mid))ans=min(ans,mid),r=mid-1;        else l=mid+1;    }    if(ans!=1e9)printf("%d",ans);    else puts("impossible");    return 0;}
阅读全文
1 0
原创粉丝点击