五星压行大师 \(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:它没有死透
标签:右点,int,题解,之环,lst,flw,无限,水管,dis
From: https://www.cnblogs.com/chang-an-22-lyh/p/18238249/wuxianzhihuan_tj