BZOJ.5120.[清華集訓2017]無限之環(費用流SPFA 黑白染色)
阿新 • • 發佈:2018-09-05
emp ons 容易 swap etc geo break res 得到
因為匹配關系是確定的,所以即使相鄰不一定有水管相連,匹配邊還是要連的。
題目鏈接
https://loj.ac/problem/2321
https://www.luogu.org/problemnew/show/P4003
容易想到最小費用最大流分配度數。
因為水管形態固定,每個點還是要拆成4個點,分別當前格子表示向上右下左方向。
然後能比較容易地得到每種狀態向其它狀態轉移的費用(比如原向上的可以流到向下)。註意比如向左向上的L,左連右,上連下,沒有上連右(日常zz)。
解決旋轉的問題後,還要處理流量從哪裏產生、結束。
因為是網格圖,容易想到黑白染色。題目中"沒有漏水水管"即格子的斷頭兩兩匹配,而匹配只發生在黑白格之間。so源點向所有白格子連邊,所有黑格子向匯點連邊。
SPFA單路增廣好慢啊,等下學一波多路增廣。https://www.luogu.org/recordnew/show/7755635
//7048kb 11328ms #include <queue> #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> //#define gc() getchar() #define MAXIN 200000 #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) #define OK(i,j) (1<=(i)&&(i)<=n&&1<=(j)&&(j)<=m) const int N=1e4+5,M=N*30; int n,m,src,des,Enum,H[N],nxt[M],fr[M],to[M],cap[M],cost[M],pre[N]; std::queue<int> q; char IN[MAXIN],*SS=IN,*TT=IN; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } inline void AE(int u,int v,int c,bool flag) { if(flag) std::swap(u,v);//黑→白 把邊反向 to[++Enum]=v, fr[Enum]=u, nxt[Enum]=H[u], cost[Enum]=c, cap[Enum]=1, H[u]=Enum; to[++Enum]=u, fr[Enum]=v, nxt[Enum]=H[v], cost[Enum]=-c, cap[Enum]=0, H[v]=Enum; } bool SPFA() { static int dis[N]; static bool inq[N]; memset(dis,0x3f,sizeof dis); dis[src]=0, q.push(src); while(!q.empty()) { int x=q.front(); q.pop(), inq[x]=0;//!... for(int v,i=H[x]; i; i=nxt[i]) if(cap[i] && dis[v=to[i]]>dis[x]+cost[i]) pre[v]=i, dis[v]=dis[x]+cost[i], !inq[v]&&(q.push(v),inq[v]=1); } return dis[des]<0x3f3f3f3f; } inline int Augment() { int res=0; for(int i=des; i!=src; i=fr[pre[i]]) res+=cost[pre[i]], --cap[pre[i]], ++cap[pre[i]^1]; return res; } int MCMF(int &cost) { int res=0; while(SPFA()) cost+=Augment(), ++res; return res; } int main() { n=read(),m=read(); int tot=0; int id[n+1][m+1][4]; for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) for(int k=0; k<4; ++k) id[i][j][k]=++tot; Enum=1, src=0, des=++tot; bool f; int flow=0; for(int i=1; i<=n; ++i) for(int j=1,s; j<=m; ++j)//0上 1右 2下 3左 {//左 下 右 上 s=read(), f=(i+j)&1; int u=f?des:src,up=id[i][j][0],ri=id[i][j][1],down=id[i][j][2],le=id[i][j][3]; if(s&1) AE(u,up,0,f), flow+=f^1; if(s&2) AE(u,ri,0,f), flow+=f^1; if(s&4) AE(u,down,0,f), flow+=f^1; if(s&8) AE(u,le,0,f), flow+=f^1; // if(!f) // for(int k=0; k<4; ++k) // if(s>>k&1) AE(src,id[i][j][k],0,0), ++flow; // else ;//else! // else for(int k=0; k<4; ++k) if(s>>k&1) AE(id[i][j][k],des,0,0); if(!f) { if(OK(i-1,j)) AE(up,id[i-1][j][2],0,0); if(OK(i,j-1)) AE(le,id[i][j-1][1],0,0); if(OK(i+1,j)) AE(down,id[i+1][j][0],0,0); if(OK(i,j+1)) AE(ri,id[i][j+1][3],0,0); } switch(s) { case 0: break; case 1: AE(up,le,1,f), AE(up,ri,1,f), AE(up,down,2,f); break; case 2: AE(ri,up,1,f), AE(ri,down,1,f), AE(ri,le,2,f); break; case 3: AE(up,down,1,f), AE(ri,le,1,f); break; case 4: AE(down,le,1,f), AE(down,ri,1,f), AE(down,up,2,f); break; case 5: break; case 6: AE(ri,le,1,f), AE(down,up,1,f); break; case 7: AE(up,le,1,f), AE(down,le,1,f), AE(ri,le,2,f); break; case 8: AE(le,up,1,f), AE(le,down,1,f), AE(le,ri,2,f); break; case 9: AE(le,ri,1,f), AE(up,down,1,f); break; case 10: break; case 11: AE(le,down,1,f), AE(ri,down,1,f), AE(up,down,2,f); break; case 12: AE(le,ri,1,f), AE(down,up,1,f); break; case 13: AE(up,ri,1,f), AE(down,ri,1,f), AE(le,ri,2,f); break; case 14: AE(le,up,1,f), AE(ri,up,1,f), AE(down,up,2,f); break; case 15: break; } } int cost=0; if(MCMF(cost)==flow) printf("%d\n",cost); else puts("-1"); return 0; }
BZOJ.5120.[清華集訓2017]無限之環(費用流SPFA 黑白染色)