五星压行大师 \(lyh\) 表示:这是难得能让他的代码长度打破百行大关的题目(182行)。
首先,根据科技与狠活,本题可以黑白染色。源点联向白格,黑格连向汇点。
发现每个格子都可以连向四个方向,所以可以建立四个点,代表水管连到了上下左右四个方向。
设四元组 \((x,y,z,p)\) 表示水管初始状态下,是否联向上、右、下、左。若 \(x==1\),则从源点联向上点(黑格则从上点联向汇点),以此类推。
例如:格子是白格,代表的水管初始状态接口在上和右,我们就从源点联向格子上点和右点;格子是黑格,就从上点和右点联向汇点。
当然,相邻格子间的上下左右是相通的,要从白格的上下左右点联向上方格子的下点、下方格子的上点、左方格子的右点、右方格子的左点。
我们用样例 1 做例子:
由于这些边都是生来就有的,所以不用支付任何费用,流量都为 1,记为 \((1,0)\)。
由于水管可以旋转,所以我们肯定还需要再连一些边。
当然,直水管不能旋转,十字型水管转了没用,所以不用考虑。
由于黑格只需要和白格反着来就可以,所以只讨论白格:
-
Q形管(只伸出一根水管)
我们以 \((1,0,0,0)\) 这样的水管为例。
发现旋转一次可以到达左点或右点,两次可以到达下点。
那么从上点向左、右点连 \((1,1)\),向下点连 \((1,2)\)。 -
T形管(伸出三根水管)
我们以 \((1,1,1,0)\) 这样的水管为例。
发现旋转一次上、下点为 0,两次右点为 0,而旋转后左点都为 1。
因而可以看作上、下、右点变成了左点。
根据 Q形管 思路,上点、下点、右点向左点连 \((1,1),(1,1),(1,2)\)。 -
L形管(伸出相邻两根水管)
我们以 \((1,1,0,0)\) 这样的水管为例。
根据上述思路,可以很快想到上点向下点连 \((1,1)\),右点向左点连 \((1,1)\)。
旋转两次相当于同时经过上面两条边,所以不连。
我们将完整版的图再画一下(新增蓝、粉边都是 \((1,1)\),其余为 \((1,2)\)):
假如不漏水,一定会经过 \(sm=\sum(x+y+z+p)\) 条边。
发现每一条增广路经过且只经过 2 条水管,所以当最大流 \(<sm\) 时,输出 -1。
其他情况下,答案即为最小费用。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=14005,M=30005;
int n,m,s,t,k=1,h[N],vis[N];
int to[M],nxt[M],w[M],f[M];
int lst[N],flw[N],dis[N],sm;
int sh(int u,int v){return 4*(u*m-m+v-1)+1;
}int xi(int u,int v){return 4*(u*m-m+v-1)+2;
}int zu(int u,int v){return 4*(u*m-m+v-1)+3;
}int yo(int u,int v){return 4*(u*m-m+v-1)+4;
}void add(int x,int y,int z,int a){w[++k]=z;f[k]=a;to[k]=y;nxt[k]=h[x];h[x]=k;f[++k]=-a;to[k]=x;nxt[k]=h[y];h[y]=k;
}queue<int>q;
int spfa(){while(q.size()) q.pop();memset(lst,-1,sizeof(lst));memset(vis,0,sizeof(vis));memset(dis,127,sizeof(dis));flw[s]=1e9;dis[s]=0;q.push(s);while(q.size()){int x=q.front();q.pop();vis[x]=0;for(int i=h[x];i;i=nxt[i]){int y=to[i],vl=w[i];if(vl&&dis[y]>dis[x]+f[i]){lst[y]=i;flw[y]=min(flw[x],vl);dis[y]=dis[x]+f[i];if(!vis[y])q.push(y),vis[y]=1;}}}return lst[t]!=-1;
}int mxflw,mncst;
void MCMF(){while(spfa()){mxflw+=flw[t];mncst+=dis[t]*flw[t];for(int i=t;i!=s;i=to[lst[i]^1])w[lst[i]]-=flw[t],w[lst[i]^1]+=flw[t];}if(mxflw*2!=sm) cout<<-1;else cout<<mncst;
}void white(int l,int u,int v){if(u>1) add(sh(u,v),xi(u-1,v),1,0);if(u<n) add(xi(u,v),sh(u+1,v),1,0);if(v>1) add(zu(u,v),yo(u,v-1),1,0);if(v<m) add(yo(u,v),zu(u,v+1),1,0);if(!l) return;int x=0,y=0,z=0,p=0;if(l&1) x=1;if(l&2) y=1;if(l&4) z=1;if(l&8) p=1;sm+=x+y+z+p;if(x) add(s,sh(u,v),1,0);if(z) add(s,xi(u,v),1,0);if(p) add(s,zu(u,v),1,0);if(y) add(s,yo(u,v),1,0);if(x&&!y&&z&&!p) return;if(!x&&y&&!z&&p) return;if(x&&y&&z&&p) return;if(x&&!y&&!z&&!p){add(sh(u,v),xi(u,v),1,2);add(sh(u,v),zu(u,v),1,1);add(sh(u,v),yo(u,v),1,1);}if(!x&&y&&!z&&!p){add(yo(u,v),sh(u,v),1,1);add(yo(u,v),zu(u,v),1,2);add(yo(u,v),xi(u,v),1,1);}if(!x&&!y&&z&&!p){add(xi(u,v),sh(u,v),1,2);add(xi(u,v),zu(u,v),1,1);add(xi(u,v),yo(u,v),1,1);}if(!x&&!y&&!z&&p){add(zu(u,v),sh(u,v),1,1);add(zu(u,v),yo(u,v),1,2);add(zu(u,v),xi(u,v),1,1);}if(x&&y&&z&&!p){add(sh(u,v),zu(u,v),1,1);add(yo(u,v),zu(u,v),1,2);add(xi(u,v),zu(u,v),1,1);}if(x&&y&&!z&&p){add(sh(u,v),xi(u,v),1,2);add(yo(u,v),xi(u,v),1,1);add(zu(u,v),xi(u,v),1,1);}if(x&&!y&&z&&p){add(sh(u,v),yo(u,v),1,1);add(zu(u,v),yo(u,v),1,2);add(xi(u,v),yo(u,v),1,1);}if(!x&&y&&z&&p){add(xi(u,v),sh(u,v),1,2);add(yo(u,v),sh(u,v),1,1);add(zu(u,v),sh(u,v),1,1);}if(!x&&!y&&z&&p){add(xi(u,v),sh(u,v),1,1);add(zu(u,v),yo(u,v),1,1);}if(x&&y&&!z&&!p){add(sh(u,v),xi(u,v),1,1);add(yo(u,v),zu(u,v),1,1);}if(x&&!y&&!z&&p){add(sh(u,v),xi(u,v),1,1);add(zu(u,v),yo(u,v),1,1);}if(!x&&y&&z&&!p){add(xi(u,v),sh(u,v),1,1);add(yo(u,v),zu(u,v),1,1);}
}void black(int l,int u,int v){if(!l) return;int x=0,y=0,z=0,p=0;if(l&1) x=1;if(l&2) y=1;if(l&4) z=1;if(l&8) p=1;sm+=x+y+z+p;if(x) add(sh(u,v),t,1,0);if(z) add(xi(u,v),t,1,0);if(p) add(zu(u,v),t,1,0);if(y) add(yo(u,v),t,1,0);if(x&&!y&&z&&!p) return;if(!x&&y&&!z&&p) return;if(x&&y&&z&&p) return;if(x&&!y&&!z&&!p){add(xi(u,v),sh(u,v),1,2);add(zu(u,v),sh(u,v),1,1);add(yo(u,v),sh(u,v),1,1);}if(!x&&y&&!z&&!p){add(sh(u,v),yo(u,v),1,1);add(zu(u,v),yo(u,v),1,2);add(xi(u,v),yo(u,v),1,1);}if(!x&&!y&&z&&!p){add(sh(u,v),xi(u,v),1,2);add(zu(u,v),xi(u,v),1,1);add(yo(u,v),xi(u,v),1,1);}if(!x&&!y&&!z&&p){add(sh(u,v),zu(u,v),1,1);add(yo(u,v),zu(u,v),1,2);add(xi(u,v),zu(u,v),1,1);}if(x&&y&&z&&!p){add(zu(u,v),sh(u,v),1,1);add(zu(u,v),yo(u,v),1,2);add(zu(u,v),xi(u,v),1,1);}if(x&&y&&!z&&p){add(xi(u,v),sh(u,v),1,2);add(xi(u,v),yo(u,v),1,1);add(xi(u,v),zu(u,v),1,1);}if(x&&!y&&z&&p){add(yo(u,v),sh(u,v),1,1);add(yo(u,v),zu(u,v),1,2);add(yo(u,v),xi(u,v),1,1);}if(!x&&y&&z&&p){add(sh(u,v),xi(u,v),1,2);add(sh(u,v),yo(u,v),1,1);add(sh(u,v),zu(u,v),1,1);}if(!x&&!y&&z&&p){add(sh(u,v),xi(u,v),1,1);add(yo(u,v),zu(u,v),1,1);}if(x&&y&&!z&&!p){add(xi(u,v),sh(u,v),1,1);add(zu(u,v),yo(u,v),1,1);}if(x&&!y&&!z&&p){add(xi(u,v),sh(u,v),1,1);add(yo(u,v),zu(u,v),1,1);}if(!x&&y&&z&&!p){add(sh(u,v),xi(u,v),1,1);add(zu(u,v),yo(u,v),1,1);}
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;t=n*m*4+1;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x;cin>>x;if((i+j)&1) black(x,i,j);else white(x,i,j);}MCMF();return 0;
}//spfa:它没有死透