BZOJ 5120: [2017國家集訓隊測試]無限之環(費用流)
阿新 • • 發佈:2018-12-14
解題思路
神仙題。調了一個晚上+半個上午。。這道咋看咋都不像圖論的題竟然用費用流做,將行+列為奇數的點和偶數的點分開,也就是匹配問題,然後把一個點複製四份,分別代表這個點的上下左右接頭,如果有這個接頭就加一個費用為\(0\),流量為\(1\)的邊,如果沒有要分情況討論,因為從源點到這個點的流量是固定的,當只有一個接頭時,可以讓這個點向自己其餘三個點連費用為\(1\),流量為\(1\)的邊,當有兩個接頭並且兩個接頭相鄰時,讓這個點的兩個接頭分別與對應的方向連邊,當有三個接頭時,讓那個沒有的接頭向相鄰的連費用為\(1\)的邊,向相對的連費用為\(2\)的邊。然後一邊費用流就行了。程式碼比較醜。建圖寫挫了。。
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cstdlib> using namespace std; const int MAXN = 10005; const int MAXM = 100005; const int inf = 0x3f3f3f3f; const int zz[4] = {1,2,4,8}; // 0 1 2 3 inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) f=ch=='0'?0:1,ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return f?x:-x; } int n,m,head[MAXN],to[MAXM<<1],nxt[MAXM<<1],val[MAXM<<1],cost[MAXM<<1],pre[MAXN]; int S,T,cnt=1,maxflow,ans,dis[MAXN],ch[MAXN][5],num,tot,sum,pos[2005][2005]; int incf[MAXN],all; bool vis[MAXN]; queue<int> Q; inline void add(int bg,int ed,int z,int w){ to[++cnt]=ed,nxt[cnt]=head[bg],val[cnt]=z,cost[cnt]=w,head[bg]=cnt; } inline void solve1(int p,int x,int op){ for(int i=0;i<=3;i++) if((x&zz[i])) { if(op&1) add(p,ch[p][i],1,0),add(ch[p][i],p,0,0); else add(ch[p][i],p,1,0),add(p,ch[p][i],0,0); if(i<2) { if(op&1) add(p,ch[p][i+2],1,2),add(ch[p][i+2],p,0,-2); else add(ch[p][i+2],p,1,2),add(p,ch[p][i+2],0,-2); } else { if(op&1) add(p,ch[p][i-2],1,2),add(ch[p][i-2],p,0,-2); else add(ch[p][i-2],p,1,2),add(p,ch[p][i-2],0,-2); } if(op&1){ add(p,ch[p][(i+1)%4],1,1),add(ch[p][(i+1)%4],p,0,-1); add(p,ch[p][(i+3)%4],1,1),add(ch[p][(i+3)%4],p,0,-1); } else{ add(ch[p][(i+1)%4],p,1,1),add(p,ch[p][(i+1)%4],0,-1); add(ch[p][(i+3)%4],p,1,1),add(p,ch[p][(i+3)%4],0,-1); } } } inline void solve2(int p,int x,int op){ if(x==5 || x==10){ for(int i=0;i<=3;i++) if(x&zz[i]){ if(op&1) add(p,ch[p][i],1,0),add(ch[p][i],p,0,0); else add(ch[p][i],p,1,0),add(p,ch[p][i],0,0); } return ; } for(int i=0;i<=3;i++){ if(x&zz[i]){ if(op&1) add(p,ch[p][i],1,0),add(ch[p][i],p,0,0); else add(ch[p][i],p,1,0),add(p,ch[p][i],0,0); } else{ if(i<2) { if((op&1)) add(ch[p][i+2],ch[p][i],1,1),add(ch[p][i],ch[p][i+2],0,-1); else add(ch[p][i],ch[p][i+2],1,1),add(ch[p][i+2],ch[p][i],0,-1); } else { if((op&1)) add(ch[p][i-2],ch[p][i],1,1),add(ch[p][i],ch[p][i-2],0,-1); else add(ch[p][i],ch[p][i-2],1,1),add(ch[p][i-2],ch[p][i],0,-1); } } } } inline void solve3(int p,int x,int op){ for(int i=0;i<=3;i++){ if(x&zz[i]){ if(op&1) add(p,ch[p][i],1,0),add(ch[p][i],p,0,0); else add(ch[p][i],p,1,0),add(p,ch[p][i],0,0); } else { if((op&1)){ add(ch[p][(i+1)%4],ch[p][i],1,1); add(ch[p][i],ch[p][(i+1)%4],0,-1); add(ch[p][(i+3)%4],ch[p][i],1,1); add(ch[p][i],ch[p][(i+3)%4],0,-1); if(i<2) { add(ch[p][i+2],ch[p][i],1,2); add(ch[p][i],ch[p][i+2],0,-2); } else { add(ch[p][i-2],ch[p][i],1,2); add(ch[p][i],ch[p][i-2],0,-2); } } else{ add(ch[p][i],ch[p][(i+1)%4],1,1); add(ch[p][(i+1)%4],ch[p][i],0,-1); add(ch[p][i],ch[p][(i+3)%4],1,1); add(ch[p][(i+3)%4],ch[p][i],0,-1); if(i<2) { add(ch[p][i],ch[p][i+2],1,2); add(ch[p][i+2],ch[p][i],0,-2); } else { add(ch[p][i],ch[p][i-2],1,2); add(ch[p][i-2],ch[p][i],0,-2); } } } } } inline void solve4(int p,int op){ for(int i=0;i<=3;i++){ if(op&1) add(p,ch[p][i],1,0),add(ch[p][i],p,0,0); else add(ch[p][i],p,1,0),add(p,ch[p][i],0,0); } } bool spfa(){ while(Q.size()) Q.pop(); memset(dis,0x3f,sizeof(dis)); memset(vis,false,sizeof(vis)); vis[S]=1;dis[S]=0;incf[S]=inf;Q.push(S); while(Q.size()){ int x=Q.front();Q.pop();vis[x]=0; for(int i=head[x];i;i=nxt[i]){ int u=to[i]; if(dis[u]>cost[i]+dis[x] && val[i]) { dis[u]=cost[i]+dis[x]; incf[u]=min(incf[x],val[i]); pre[u]=i; if(!vis[u]) vis[u]=1,Q.push(u); } } } return (dis[T]==inf)?false:true; } inline void update(){ int x=T,i; while(x!=S){ i=pre[x]; val[i]-=incf[T]; val[i^1]+=incf[T]; x=to[i^1]; } maxflow+=incf[T]; ans+=incf[T]*dis[T]; } int main(){ n=rd(),m=rd();S=++num;T=++num;int x,p; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ x=rd();p=++num;pos[i][j]=p; for(int k=0;k<=3;k++) ch[p][k]=++num; tot=__builtin_popcount(x); if((i+j)&1) add(S,p,tot,0),add(p,S,0,0); else add(p,T,tot,0),add(T,p,0,0); if(tot==1) solve1(p,x,i+j); else if(tot==2) solve2(p,x,i+j); else if(tot==3) solve3(p,x,i+j); else solve4(p,i+j); sum+=tot; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(!((i+j)&1)) continue; if(i!=1){ add(ch[pos[i][j]][0],ch[pos[i-1][j]][2],1,0); add(ch[pos[i-1][j]][2],ch[pos[i][j]][0],0,0); } if(j!=1){ add(ch[pos[i][j]][3],ch[pos[i][j-1]][1],1,0); add(ch[pos[i][j-1]][1],ch[pos[i][j]][3],0,0); } if(i!=n){ add(ch[pos[i][j]][2],ch[pos[i+1][j]][0],1,0); add(ch[pos[i+1][j]][0],ch[pos[i][j]][2],0,0); } if(j!=m){ add(ch[pos[i][j]][1],ch[pos[i][j+1]][3],1,0); add(ch[pos[i][j+1]][3],ch[pos[i][j]][1],0,0); } } if(sum&1) {puts("-1");return 0;} sum>>=1; while(spfa()) update(); if(maxflow!=sum) puts("-1"); else printf("%d\n",ans); return 0; }