无限之环 题解

五星压行大师 \(lyh\) 表示:这是难得能让他的代码长度打破百行大关的题目(182行)。

首先,根据科技与狠活,本题可以黑白染色。源点联向白格,黑格连向汇点。

发现每个格子都可以连向四个方向,所以可以建立四个点,代表水管连到了上下左右四个方向。

设四元组 \((x,y,z,p)\) 表示水管初始状态下,是否联向上、右、下、左。若 \(x==1\),则从源点联向上点(黑格则从上点联向汇点),以此类推。

例如:格子是白格,代表的水管初始状态接口在上和右,我们就从源点联向格子上点和右点;格子是黑格,就从上点和右点联向汇点。

当然,相邻格子间的上下左右是相通的,要从白格的上下左右点联向上方格子的下点、下方格子的上点、左方格子的右点、右方格子的左点。

我们用样例 1 做例子:

由于这些边都是生来就有的,所以不用支付任何费用,流量都为 1,记为 \((1,0)\)

由于水管可以旋转,所以我们肯定还需要再连一些边。

当然,直水管不能旋转,十字型水管转了没用,所以不用考虑。

由于黑格只需要和白格反着来就可以,所以只讨论白格:

  1. Q形管(只伸出一根水管)
    我们以 \((1,0,0,0)\) 这样的水管为例。
    发现旋转一次可以到达左点或右点,两次可以到达下点。
    那么从上点向左、右点连 \((1,1)\),向下点连 \((1,2)\)

  2. T形管(伸出三根水管)
    我们以 \((1,1,1,0)\) 这样的水管为例。
    发现旋转一次上、下点为 0,两次右点为 0,而旋转后左点都为 1。
    因而可以看作上、下、右点变成了左点。
    根据 Q形管 思路,上点、下点、右点向左点连 \((1,1),(1,1),(1,2)\)

  3. 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:它没有死透
posted @ 2024-06-08 09:15  长安一片月_22  阅读(6)  评论(0编辑  收藏  举报