[UOJ336]無限之環
阿新 • • 發佈:2018-11-09
題目的要求就是每個接頭都有且僅有一個與其相連的接頭,所以不妨給每個接頭$1$的流量,對整個網格圖黑白染色後(源點$\mathop\rightarrow\limits^\infty$黑點,白點$\mathop\rightarrow\limits^\infty$匯點)跑最大流即可,剩下的問題就是給旋轉水管安排合適的費用
把網格中的格子和邊都看成點,先對每個格子按照形狀向四周連邊$(1,0)$,然後用恰當的建圖來表示費用和糾正流量
對$1$接頭,轉一次可以改變流量到相鄰的兩個接頭,轉兩次可以改變流量到對面的接頭
對$2$接頭,轉一次相當於把一個接頭的流量改到對面,連了這兩條邊後發現恰好滿足轉兩次的需求
對$3$接頭,轉一次相當於一個接頭的流量改到相鄰,轉兩次相當於將$3$個接頭中間的接頭改到對面,但因為每個接頭都只能有$1$的流量經過,所以還要增加一點一邊來限流
$4$接頭就直接連了
總的來說就是兩點:1.黑白染色確保能在網格上的邊產生流量;2.考慮旋轉造成的實際影響,進而構造相應的圖
無解就是黑白格接頭不相等或跑出來的最大流和黑格接頭不相等
#include<stdio.h> #include<string.h> #include<queue> using namespace std; const int inf=2147483647,go[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; int h[8010],nex[32010],to[32010],cap[32010],cos[32010],M=1,S,T; void ins(int a,int b,int c,int d){ M++; to[M]=b; cap[M]=c; cos[M]=d; nex[M]=h[a]; h[a]=M; } void add(int a,int b,int c,int d){ ins(a,b,c,d); ins(b,a,0,-d); } int dis[8010],sum,cost,N; struct pr{ int x,d; pr(int u=0):x(u),d(dis[u]){} }t; bool operator<(pr a,pr b){return a.d>b.d;} priority_queue<pr>q; bool bfs(){ int x,i; memset(dis,63,sizeof(dis)); dis[T]=0; q.push(T); while(!q.empty()){ t=q.top(); q.pop(); x=t.x; if(t.d!=dis[x])continue; for(i=h[x];i;i=nex[i]){ if(cap[i^1]&&dis[x]-cos[i]<dis[to[i]]){ dis[to[i]]=dis[x]-cos[i]; q.push(to[i]); } } } sum+=dis[S]; for(x=1;x<=N;x++){ for(i=h[x];i;i=nex[i])cos[i]+=dis[to[i]]-dis[x]; } return dis[S]!=dis[0]; } bool aug[8010]; int dfs(int x,int flow){ if(flow==0)return 0; if(x==T){ cost+=sum*flow; return flow; } int i,us=0,t; aug[x]=1; for(i=h[x];i&&flow;i=nex[i]){ if(cap[i]&&!cos[i]&&!aug[to[i]]){ t=dfs(to[i],min(flow,cap[i])); cap[i]-=t; cap[i^1]+=t; us+=t; flow-=t; } } if(!flow)aug[x]=0; return us; } int costflow(){ int s,w; s=0; do{ do{ memset(aug,0,sizeof(aug)); w=dfs(S,inf); s+=w; }while(w); }while(bfs()); return s; } int cnt[16],rot[16],n,m; int type(int x){ if(cnt[x]==2)return x==5||x==10?0:2; return cnt[x]; } int p(int x,int y){ return(x-1)*m+y; } int p(int x,int y,int f){ f&=3; if(f==0)return(x-1)*m+y+n*m; if(f==1)return(x-1)*(m+1)+y+1+n*m+(n+1)*m; if(f==2)return x*m+y+n*m; return(x-1)*(m+1)+y+n*m+(n+1)*m; } void gao(int a,int b,int c,int d,int f){ if(f) add(a,b,c,d); else add(b,a,c,d); } int main(){ int i,j,x,s1,s2; for(i=1;i<16;i++)cnt[i]=cnt[i>>1]+(i&1); rot[2]=1; rot[4]=2; rot[6]=1; rot[8]=3; rot[9]=3; rot[11]=3; rot[12]=2; rot[13]=2; rot[14]=1; scanf("%d%d",&n,&m); S=n*m+(n+1)*m+n*(m+1)+1; N=T=S+1; s1=s2=0; for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ scanf("%d",&x); if(x==0)continue; if((i+j)&1){ s1+=cnt[x]; add(S,p(i,j),inf,0); }else{ s2+=cnt[x]; add(p(i,j),T,inf,0); } if(x==5){ gao(p(i,j),p(i,j,0),1,0,(i+j)&1); gao(p(i,j),p(i,j,2),1,0,(i+j)&1); } if(x==10){ gao(p(i,j),p(i,j,1),1,0,(i+j)&1); gao(p(i,j),p(i,j,3),1,0,(i+j)&1); } switch(type(x)){ case 1: gao(p(i,j),p(i,j,rot[x]),1,0,(i+j)&1); gao(p(i,j,rot[x]),p(i,j,rot[x]+1),1,1,(i+j)&1); gao(p(i,j,rot[x]),p(i,j,rot[x]+2),1,2,(i+j)&1); gao(p(i,j,rot[x]),p(i,j,rot[x]+3),1,1,(i+j)&1); break; case 2: gao(p(i,j),p(i,j,rot[x]),1,0,(i+j)&1); gao(p(i,j),p(i,j,rot[x]+1),1,0,(i+j)&1); gao(p(i,j,rot[x]),p(i,j,rot[x]+2),1,1,(i+j)&1); gao(p(i,j,rot[x]+1),p(i,j,rot[x]+3),1,1,(i+j)&1); break; case 3: gao(p(i,j),p(i,j,rot[x]),1,0,(i+j)&1); gao(p(i,j),p(i,j,rot[x]+1),1,0,(i+j)&1); gao(p(i,j),p(i,j,rot[x]+2),1,0,(i+j)&1); N++; gao(p(i,j,rot[x]),N,1,1,(i+j)&1); gao(p(i,j,rot[x]+1),N,1,2,(i+j)&1); gao(p(i,j,rot[x]+2),N,1,1,(i+j)&1); gao(N,p(i,j,rot[x]+3),1,0,(i+j)&1); break; case 4: gao(p(i,j),p(i,j,0),1,0,(i+j)&1); gao(p(i,j),p(i,j,1),1,0,(i+j)&1); gao(p(i,j),p(i,j,2),1,0,(i+j)&1); gao(p(i,j),p(i,j,3),1,0,(i+j)&1); break; } } } if(s1!=s2||costflow()!=s1) puts("-1"); else printf("%d",cost); }