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; }