zoukankan      html  css  js  c++  java
  • 洛谷P4003 [国家集训队2017]无限之环 网络流 最小费用最大流

    题意简述

    有一个(n imes m)棋盘,棋盘上每个格子上有一个水管。水管共有(16)种,用一个(4)位二进制数来表示当前水管向上、右、下、左有个接口。你可以旋转除了((0101)_2)((1010)_2)的其他水管,求最少的旋转次数使得水管的每一个接口所在方向都有一个相邻的水管接口与其对应。

    做法

    这种插头相关的题一般都是网络流,虽然据说插头dp可以过此题。这道题里面要求不存在单独的接口,所有的接口一一对应等价于流量平衡,那么最少的旋转次数就应该想到费用流。

    首先把整个棋盘染色,黑点连源点,白格连汇点,这些源汇点的节点流量限制为自己的格子内的接头数。那么如果流量网络满流,那就是此题有解,可以构成流量平衡的情况。

    对于每个格子,上下左右拆成四个点,表示这个格子的(4)个方向,他们的节点容量为(1),用来象征对应接口的流量平衡。

    对于一开始不能到达的方向,从初始方向连边至目标方向,费用为最少旋转次数,这样无论怎么旋转,接口对应关系依然存在。

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define in inline 
    #define ak *
    #define inf 1e9
    #define loc(i,j) ((i-1)*m+j)
    int col,cnt=1,n,m,s,t,h[10005],dis[10005],l,r,q[10005],pre[10005],vis[10005],mp[10005],ans,maxflow,preflow;
    struct did{
    	int u,next,to,f,w;
    }e[1200005];
    char qwq;
    in int read()
    {
    	int yz=0,ioi=1;qwq=getchar();
    	while(qwq<'0'||qwq>'9') ioi=qwq=='-'?~ioi+1:1,qwq=getchar();
    	while(qwq>='0'&&qwq<='9') yz=(yz<<3)+(yz<<1)+(qwq^48),qwq=getchar();
    	return yz ak ioi;
    }
    in void add(re a,re b,re c,re d)
    {
    	if(!col) swap(a,b);
    	e[++cnt]=(did){a,h[a],b,c,d},h[a]=cnt;
    	e[++cnt]=(did){b,h[b],a,0,-d},h[b]=cnt;
    }
    int spfa()
    {
    	memset(pre,0,sizeof(pre));memset(vis,0,sizeof(vis));
    	for(re i=s;i<=t;i++) dis[i]=i==s?0:inf;
    	queue<int>q;q.push(s);vis[s]=1;
    	while(!q.empty())
    	{
    		re i=q.front();vis[i]=0;q.pop();
    		for(re j=h[i],k;k=e[j].to,j;j=e[j].next)
    		if(e[j].f&&dis[k]>dis[i]+e[j].w)
    		{
    			dis[k]=dis[i]+e[j].w;pre[k]=j;
    			if(!vis[k]) q.push(k),vis[k]=1;
    		}
    	}	
    	return dis[t]<inf;
    }
    in void solve()
    {
    	re delta=inf;
    	for(re i=t,p;p=pre[i],i!=s;i=e[p^1].to)
    	delta=min(delta,e[p].f);
    	for(re i=t,p;p=pre[i],i!=s;i=e[p^1].to)
    	e[p].f-=delta,e[p^1].f+=delta;
    	maxflow+=delta;ans+=delta*dis[t];
    }
    in int f(re i,re j) {return i*(n*m+1)+j;}
    in int g(re i,re j) {return (i-1)*m+j;}
    in bool ok(re i,re j) {return (i>=1&&i<=n&&j>=1&&j<=m);}
    in void turn(re p,re x,re y,re z) {add(f(x,p),f(y,p),1,z);}
    int main()
    {
    //	freopen("infinityloop.in","r",stdin);
    //	freopen("infinityloop.out","w",stdout);
    	n=read(),m=read(); s=0;t=4*(n*m+1)+4;
    	for(re i=1;i<=n;i++) for(re j=1;j<=m;j++) mp[g(i,j)]=read();
    	for(re i=1;i<=n;i++) for(re j=1;j<=m;j++)
    	{
    		re p=g(i,j);col=(i+j)%2;
    		if(col)
    		{
    			for(re k=0;k<=3;k++) 
    			if((mp[p]>>k)&1) add(s,f(k,p),1,0),preflow++;
    		}
    		else
    		{
    			for(re k=0;k<=3;k++) 
    			if((mp[p]>>k)&1) add(t,f(k,p),1,0);
    		}
    		if(col)
            {
                if(ok(i-1,j)) add(f(0,p),f(2,g(i-1,j)),1,0);
                if(ok(i,j+1)) add(f(1,p),f(3,g(i,j+1)),1,0);
                if(ok(i+1,j)) add(f(2,p),f(0,g(i+1,j)),1,0);
                if(ok(i,j-1)) add(f(3,p),f(1,g(i,j-1)),1,0);
            }
            switch(mp[p])
            {
    			case 0: break; // 0000
    			case 5: break; // 0101
    			case 10: break; // 1010
    			case 15: break; // 1111
    			case 1: turn(p,0,1,1);turn(p,0,2,2);turn(p,0,3,1);break; // 0001
    			case 2: turn(p,1,0,1);turn(p,1,3,2);turn(p,1,2,1);break; // 0010
    			case 4: turn(p,2,1,1);turn(p,2,0,2);turn(p,2,3,1);break; // 0100
    			case 8: turn(p,3,0,1);turn(p,3,1,2);turn(p,3,2,1);break; // 1000
    			case 3: turn(p,0,2,1);turn(p,1,3,1);break; // 0011
    			case 6: turn(p,1,3,1);turn(p,2,0,1);break; // 0110
    			case 9: turn(p,0,2,1);turn(p,3,1,1);break; // 1001
    			case 12: turn(p,2,0,1);turn(p,3,1,1);break; // 1100
    			case 7: turn(p,0,3,1);turn(p,1,3,2);turn(p,2,3,1);break; // 0111
    			case 11: turn(p,0,2,2);turn(p,1,2,1);turn(p,3,2,1);break; // 1011
    			case 13: turn(p,0,1,1);turn(p,2,1,1);turn(p,3,1,2);break; // 1101
    			case 14: turn(p,3,0,1);turn(p,2,0,2);turn(p,1,0,1);break; // 1110
    		}
    	}
    	while(spfa()) solve();
    	if(maxflow!=preflow) return puts("-1"),0;
    	cout<<ans<<endl;
    }
    
    
  • 相关阅读:
    Mysql 单表查询-排序-分页-group by初识
    Mysql 单表查询where初识
    Mysql 库表操作初识
    Mysql 常见数据类型及约束
    数据库 初识
    Mysql 游标初识
    Mysql 控制结构初识
    Mysql 存储过程初识
    单链表-Python实现-jupyter->markdown 格式测试
    MySQL 触发器学习-markdown->html 格式测试
  • 原文地址:https://www.cnblogs.com/disangan233/p/11164920.html
Copyright © 2011-2022 走看看