P3191 [HNOI2007]緊急疏散EVACUATE(費用流)

P3191 [HNOI2007]緊急疏散EVACUATEios

費用流+卡常優化數組

咱們只關心一我的經過門時的時間,在空地的行走時間能夠分層維護優化

因而根據時間分層,到門的時候再計算代價,即代價$=$層數spa

每通過$1$單位時間就向下走一層code

而後就是優化:blog

1. 刪去多餘點(層):只要開和人數相同的層,由於一我的的等待時間必定小等於人數隊列

2. 能預處理的儘可能預處理get

3. register,快讀,inline等string

4. 能不用stl儘可能不用(使用stl:queue=TLE),建議手寫隊列io

複雜度$O($卡常能過$)$,詳情可看code

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
using namespace std;
#define N 200005
#define M 3000005
const int d1[4]={0,1,0,-1};
const int d2[4]={1,0,-1,0};
char a[30][30];
int n,m,nm,mx,ans,tot,S,T,v[N],p[N],id[30][30];
bool vis[N]; int h[M],L,R;
int Cnt=1,hd[N],nxt[M],ed[N],poi[M],con[M],val[M];
void adde(int x,int y,int v1,int v2){
    nxt[ed[x]]=++Cnt; hd[x]=hd[x]?hd[x]:Cnt;
    ed[x]=Cnt; poi[Cnt]=y; con[Cnt]=v1; val[Cnt]=v2;
}
inline void link(int x,int y,int v1,int v2){adde(x,y,v1,v2),adde(y,x,0,-v2);}
#define to poi[i]
bool bfs(){//普通費用流
    memset(v,63,sizeof(v)); int inf=v[0];
    h[L=1]=S; R=2; vis[S]=1; v[S]=0;
    while(L!=R){
        re int x=h[L++]; vis[x]=0;
        if(L>=M) L=1;
        for(re int i=hd[x];i;i=nxt[i])
            if(con[i]&&v[to]>v[x]+val[i]){
                v[to]=v[x]+val[i]; p[to]=i;
                if(!vis[to]){
                    vis[to]=1,h[R++]=to;
                    if(R>=M) R=1;
                }
            }
    }if(v[T]==inf) return 0;
    tot-=1; ans=max(ans,v[T]);
    for(re int u=T;u!=S;u=poi[p[u]^1])
        con[p[u]]-=1,con[p[u]^1]+=1;
    return 1;
}//由於每次流量均爲1,能夠省去流量數組
void draw(int x,int y){
    re int p=id[x][y];
    if(a[x][y]=='X') return ;
    if(a[x][y]=='D') for(re int i=1;i<=mx;++i) link(p+i*nm,T,1,i);//分層與終點連邊,代價=層數
    if(a[x][y]=='.'){
        link(S,p,1,0); ++tot;
        for(re int i=0;i<mx;++i){
            link(p+i*nm,p+(i+1)*nm,1e9,0);
            for(re int j=0;j<4;++j){
                int rx=x+d1[j],ry=y+d2[j];
                if(a[rx][ry]=='X') continue;
                link(p+i*nm,id[rx][ry]+(i+1)*nm,1e9,0);//與四周連邊
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);  S=N-4; T=N-3; nm=n*m;
    for(re int i=1;i<=n;++i) scanf("%s",a[i]+1);
    for(re int i=1;i<=n;++i)
        for(re int j=1;j<=m;++j)
            mx+=(a[i][j]=='.'),id[i][j]=(i-1)*m+j;//mx:人數,建圖須要的層數
    for(re int i=1;i<=n;++i) for(re int j=1;j<=m;++j) draw(i,j);
    while(bfs()) ;
    if(tot) puts("impossible");
    else printf("%d",ans);
    return 0;
}
相關文章
相關標籤/搜索