• 【洛谷P4003】无限之环【费用流】


    题目大意:

    题目链接:https://www.luogu.org/problem/P4003
    曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏:
    游戏在一个n×mn imes m的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在
    格某些方向的边界的中点有接口,所有水管的粗细都相同,所以如果两个相邻方格的
    共边界的中点都有接头,那么可以看作这两个接头互相连接。水管有以下15种形状:
    在这里插入图片描述
    游戏开始时,棋盘中水管可能存在漏水的地方。

    形式化地:如果存在某个接头,没有和其它接头相连接,那么它就是一个漏水的

    地方。

    玩家可以进行一种操作:选定一个含有非.直.线.型.水管的方格,将其中的水管绕方格

    中心顺时针或逆时针旋转 90 度。

    直线型水管是指左图里中间一行的两种水管。

    现给出一个初始局面,请问最少进行多少次操作可以使棋盘上不存在漏水的地方。


    思路:

    这道题可以把水流看成流量,旋转次数看成费用,这样就基本是一个费用流的板子。
    但是这道题建模还是比较难。主要有以下两个问题:

    1. 如何保证每一条水管都有流量?
    2. 如何处理旋转产生的费用?

    我们先把每一个点拆成五个点,分别是往上下左右流的边和与原点汇点流的边。姑且把后者称作总点。
    那么为了保证每条边都满流,我们必须把点黑白染色,白点的总点连原点,然后原点连向上下左右;黑点的总点连汇点,然后从上下左右连总点。之后所有白点的上下左右点分别连黑点的上下左右点。
    这样我们就把整个图建好了。其中我们把每一条边拆成了两个点之间分别的两条边,所以最终的流量会是我们建的两点之间的边的个数的一半。
    在这里插入图片描述
    那么费用应该如何处理呢?
    我们来分类讨论一下。

    注意:黑点与白点的连线正好完全相反。例如白点的连线为(x,y)(x,y),那么黑点的连线为(y,x)(y,x)


    在这里插入图片描述
    这种情况非常简单。我们以水管朝上为例。那么如果我们要让水管朝左或者朝右,那么只要花费1的费用即可。所以从上向左右分别连费用为1的边,同理,从上向下连费用为2的边。


    在这里插入图片描述
    由于题目要求直管不能旋转,所以就不用再内部连任何的边。


    在这里插入图片描述
    如果把这个水管顺时针旋转90°90°,那么就相当于把左边的水管放在了右边,同理,逆时针就相当于把上面的水管放在了下面。
    那么就从上到下,从左到右分别连一条费用为1的边。
    此时如果旋转180°180°的费用正好为2,和题目要求一致。


    在这里插入图片描述
    这种水管也很好理解,旋转90°90°就相当于把左边或右边的水管转移到下面。那么就从左右向下连一条费用为1的边。同理,从上到下连一条费用为2的边。


    在这里插入图片描述
    这个转了和没转没有区别,所以就不用再内部连边了。


    注意除了上述连边外,还有上下左右边和总点的连边、只要把这个水管原本的边和总点连接即可。
    主要还是靠理解,这个连边在图上不是很好画,代码就更加看不懂。。。
    这是我至今为止连边最长的费用流。
    并且这道题用普通的ekek会T,用zkwzkw费用流就可以了。
    spfaspfa最好加上slfslfLLLLLL优化。


    代码:

    #include <queue>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=1000010,Inf=1e9;
    int n,m,S,T,maxflow,cnt,cost,tot=1,head[N],dis[N];
    bool vis[N];
    
    struct edge
    {
    	int next,to,from,flow,cost;
    }e[N];
    
    int U(int x){return x+n*m;}
    int D(int x){return x+n*m*2;}
    int L(int x){return x+n*m*3;}
    int R(int x){return x+n*m*4;}
    
    int read()
    {
    	int d=0;
    	char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch))	
    		d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    int pos(int x)
    {
    	int a=(x&1)>0,b=(x&2)>0,c=(x&4)>0,d=(x&8)>0;
    	if (a+b+c+d==1) return 1;
    	if (a+b+c+d==2)
    	{
    		if ((a&c) || (b&d)) return 2;
    			else return 3;
    	}
    	if (a+b+c+d==3) return 4;
    	if (a+b+c+d==4) return 5;
    }
    
    void add(int from,int to,int flow,int cost)
    {
    	e[++tot].to=to;
    	e[tot].from=from;
    	e[tot].flow=flow;
    	e[tot].cost=cost;
    	e[tot].next=head[from];
    	head[from]=tot;
    	
    	swap(from,to);
    	e[++tot].to=to;
    	e[tot].from=from;
    	e[tot].flow=0;
    	e[tot].cost=-cost;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    bool spfa()
    {
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	deque<int> q;
    	q.push_back(T);
    	dis[T]=0; vis[T]=1;
    	int sum=0;
    	while (q.size())
    	{
    		int u=q.front();
    		while (dis[u]*q.size()>sum)
    		{
    			q.push_back(u);
    			q.pop_front();
    			u=q.front();
    		}
    		q.pop_front();
    		vis[u]=0; 
    		sum-=dis[u];
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (e[i^1].flow && dis[v]>dis[u]+e[i^1].cost)
    			{
    				dis[v]=dis[u]+e[i^1].cost;
    				if (!vis[v])
    				{
    					vis[v]=1;
    					if (q.size() && dis[v]>dis[q.front()]) q.push_back(v);
    						else q.push_front(v);
    					sum+=dis[v];
    				}
    			}
    		}
    	}
    	return dis[S]<Inf;
    }
    
    int dfs(int x,int flow)
    {
        int low=0;
        if (x==T)
        {
        	vis[T]=1;
            return flow;
        }
        int used=0;
        vis[x]=1;
        for (int i=head[x];~i;i=e[i].next)
        {
            int y=e[i].to;
            if (!vis[y] && dis[y]==dis[x]-e[i].cost && e[i].flow)
            {
                low=dfs(y,min(e[i].flow,flow-used));
                if (low)
                {
                	cost+=e[i].cost*low;
                    used+=low;
                    e[i].flow-=low;
                    e[i^1].flow+=low;
                    if (used==flow) break;
                }
            }
        }
        return used;
    }
    
    void zkw()
    {
    	while (spfa())
    	{
    		vis[T]=1;
    		while (vis[T])
    		{
    			memset(vis,0,sizeof(vis));
    			maxflow+=dfs(S,Inf);
    		}
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	S=N-1; T=N-2;
    	n=read(); m=read();
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    		{
    			int x=i*m-m+j,y,opt;
    			y=read();
    			opt=pos(y);
    			if ((i+j)&1)
    			{
    				if (opt==1)
    				{
    					if (y&1) add(U(x),x,1,0),add(L(x),U(x),1,1),add(R(x),U(x),1,1),add(D(x),U(x),1,2);
    					if (y&2) add(R(x),x,1,0),add(U(x),R(x),1,1),add(D(x),R(x),1,1),add(L(x),R(x),1,2);
    					if (y&4) add(D(x),x,1,0),add(L(x),D(x),1,1),add(R(x),D(x),1,1),add(U(x),D(x),1,2);
    					if (y&8) add(L(x),x,1,0),add(U(x),L(x),1,1),add(D(x),L(x),1,1),add(R(x),L(x),1,2);
    					cnt++;
    				}
    				if (opt==2)
    				{
    					if (y&1) add(U(x),x,1,0),add(D(x),x,1,0);
    					if (y&2) add(L(x),x,1,0),add(R(x),x,1,0);
    					cnt+=2;
    				}
    				if (opt==3)
    				{
    					if ((y&1) && (y&2)) add(U(x),x,1,0),add(R(x),x,1,0),add(D(x),U(x),1,1),add(L(x),R(x),1,1);
    					if ((y&2) && (y&4)) add(D(x),x,1,0),add(R(x),x,1,0),add(U(x),D(x),1,1),add(L(x),R(x),1,1);
    					if ((y&4) && (y&8)) add(D(x),x,1,0),add(L(x),x,1,0),add(U(x),D(x),1,1),add(R(x),L(x),1,1);
    					if ((y&8) && (y&1)) add(U(x),x,1,0),add(L(x),x,1,0),add(D(x),U(x),1,1),add(R(x),L(x),1,1);
    					cnt+=2;
    				}
    				if (opt==4)
    				{
    					if (!(y&1))
    						add(D(x),x,1,0),add(L(x),x,1,0),add(R(x),x,1,0),add(U(x),D(x),1,2),add(U(x),R(x),1,1),add(U(x),L(x),1,1);
    					if (!(y&2))
    						add(D(x),x,1,0),add(L(x),x,1,0),add(U(x),x,1,0),add(R(x),L(x),1,2),add(R(x),U(x),1,1),add(R(x),D(x),1,1);
    					if (!(y&4))
    						add(U(x),x,1,0),add(L(x),x,1,0),add(R(x),x,1,0),add(D(x),U(x),1,2),add(D(x),R(x),1,1),add(D(x),L(x),1,1);
    					if (!(y&8))
    						add(U(x),x,1,0),add(D(x),x,1,0),add(R(x),x,1,0),add(L(x),R(x),1,2),add(L(x),U(x),1,1),add(L(x),D(x),1,1);
    					cnt+=3;
    				}
    				if (opt==5) add(U(x),x,1,0),add(D(x),x,1,0),add(L(x),x,1,0),add(R(x),x,1,0),cnt+=4;
    			}
    			else
    			{
    				if (opt==1)
    				{
    					if (y&1) add(x,U(x),1,0),add(U(x),L(x),1,1),add(U(x),R(x),1,1),add(U(x),D(x),1,2);
    					if (y&2) add(x,R(x),1,0),add(R(x),U(x),1,1),add(R(x),D(x),1,1),add(R(x),L(x),1,2);
    					if (y&4) add(x,D(x),1,0),add(D(x),L(x),1,1),add(D(x),R(x),1,1),add(D(x),U(x),1,2);
    					if (y&8) add(x,L(x),1,0),add(L(x),U(x),1,1),add(L(x),D(x),1,1),add(L(x),R(x),1,2);
    					cnt++;
    				}
    				if (opt==2)
    				{
    					if (y&1) add(x,U(x),1,0),add(x,D(x),1,0);
    					if (y&2) add(x,L(x),1,0),add(x,R(x),1,0);
    					cnt+=2;
    				}
    				if (opt==3)
    				{
    					if ((y&1) && (y&2)) add(x,U(x),1,0),add(x,R(x),1,0),add(U(x),D(x),1,1),add(R(x),L(x),1,1);
    					if ((y&2) && (y&4)) add(x,D(x),1,0),add(x,R(x),1,0),add(D(x),U(x),1,1),add(R(x),L(x),1,1);
    					if ((y&4) && (y&8)) add(x,D(x),1,0),add(x,L(x),1,0),add(D(x),U(x),1,1),add(L(x),R(x),1,1);
    					if ((y&8) && (y&1)) add(x,U(x),1,0),add(x,L(x),1,0),add(U(x),D(x),1,1),add(L(x),R(x),1,1);
    					cnt+=2;
    				}
    				if (opt==4)
    				{
    					if (!(y&1))
    						add(x,D(x),1,0),add(x,L(x),1,0),add(x,R(x),1,0),add(D(x),U(x),1,2),add(R(x),U(x),1,1),add(L(x),U(x),1,1);
    					if (!(y&2))
    						add(x,D(x),1,0),add(x,L(x),1,0),add(x,U(x),1,0),add(L(x),R(x),1,2),add(U(x),R(x),1,1),add(D(x),R(x),1,1);
    					if (!(y&4))
    						add(x,U(x),1,0),add(x,L(x),1,0),add(x,R(x),1,0),add(U(x),D(x),1,2),add(R(x),D(x),1,1),add(L(x),D(x),1,1);
    					if (!(y&8))
    						add(x,U(x),1,0),add(x,D(x),1,0),add(x,R(x),1,0),add(R(x),L(x),1,2),add(U(x),L(x),1,1),add(D(x),L(x),1,1);
    					cnt+=3;
    				}
    				if (opt==5) add(x,U(x),1,0),add(x,D(x),1,0),add(x,L(x),1,0),add(x,R(x),1,0),cnt+=4;
    			}
    			
    			if (!((i+j)&1))
    			{
    				add(S,x,Inf,0);
    				if (i>1) add(U(x),D(x-m),1,0);
    				if (i<n) add(D(x),U(x+m),1,0);
    				if (j>1) add(L(x),R(x-1),1,0);
    				if (j<m) add(R(x),L(x+1),1,0);
    			}
    			else add(x,T,Inf,0);
    		}
    	zkw();
    	if (maxflow*2==cnt) printf("%d
    ",cost);
    		else printf("-1");
    	return 0;
    }
    
  • 相关阅读:
    那些离不开的 Chrome 扩展插件
    Spring Boot 实战 —— 入门
    Maven 学习笔记
    Linux lvm 分区知识笔记
    Linux 双向 SSH 免密登录
    CentOS Yum 源搭建
    Ubuntu 系统学习
    iOS 测试三方 KIF 的那些事
    Swift 网络请求数据与解析
    iOS Plist 文件的 增 删 改
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998078.html
Copyright © 2020-2023  润新知