题目的要求就是每个接头都有且仅有一个与其相连的接头,所以不妨给每个接头$1$的流量,对整个网格图黑白染色后(源点$\mathop\rightarrow\limits^\infty$黑点,白点$\mathop\rightarrow\limits^\infty$汇点)跑最大流即可,剩下的问题就是给旋转水管安排合适的费用

把网格中的格子和边都看成点,先对每个格子按照形状向四周连边$(1,0)$,然后用恰当的建图来表示费用和纠正流量

对$1$接头,转一次可以改变流量到相邻的两个接头,转两次可以改变流量到对面的接头

对$2$接头,转一次相当于把一个接头的流量改到对面,连了这两条边后发现恰好满足转两次的需求

对$3$接头,转一次相当于一个接头的流量改到相邻,转两次相当于将$3$个接头中间的接头改到对面,但因为每个接头都只能有$1$的流量经过,所以还要增加一点一边来限流

$4$接头就直接连了

总的来说就是两点:1.黑白染色确保能在网格上的边产生流量;2.考虑旋转造成的实际影响,进而构造相应的图

无解就是黑白格接头不相等或跑出来的最大流和黑格接头不相等

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int inf=2147483647,go[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int h[8010],nex[32010],to[32010],cap[32010],cos[32010],M=1,S,T;
void ins(int a,int b,int c,int d){
	M++;
	to[M]=b;
	cap[M]=c;
	cos[M]=d;
	nex[M]=h[a];
	h[a]=M;
}
void add(int a,int b,int c,int d){
	ins(a,b,c,d);
	ins(b,a,0,-d);
}
int dis[8010],sum,cost,N;
struct pr{
	int x,d;
	pr(int u=0):x(u),d(dis[u]){}
}t;
bool operator<(pr a,pr b){return a.d>b.d;}
priority_queue<pr>q;
bool bfs(){
	int x,i;
	memset(dis,63,sizeof(dis));
	dis[T]=0;
	q.push(T);
	while(!q.empty()){
		t=q.top();
		q.pop();
		x=t.x;
		if(t.d!=dis[x])continue;
		for(i=h[x];i;i=nex[i]){
			if(cap[i^1]&&dis[x]-cos[i]<dis[to[i]]){
				dis[to[i]]=dis[x]-cos[i];
				q.push(to[i]);
			}
		}
	}
	sum+=dis[S];
	for(x=1;x<=N;x++){
		for(i=h[x];i;i=nex[i])cos[i]+=dis[to[i]]-dis[x];
	}
	return dis[S]!=dis[0];
}
bool aug[8010];
int dfs(int x,int flow){
	if(flow==0)return 0;
	if(x==T){
		cost+=sum*flow;
		return flow;
	}
	int i,us=0,t;
	aug[x]=1;
	for(i=h[x];i&&flow;i=nex[i]){
		if(cap[i]&&!cos[i]&&!aug[to[i]]){
			t=dfs(to[i],min(flow,cap[i]));
			cap[i]-=t;
			cap[i^1]+=t;
			us+=t;
			flow-=t;
		}
	}
	if(!flow)aug[x]=0;
	return us;
}
int costflow(){
	int s,w;
	s=0;
	do{
		do{
			memset(aug,0,sizeof(aug));
			w=dfs(S,inf);
			s+=w;
		}while(w);
	}while(bfs());
	return s;
}
int cnt[16],rot[16],n,m;
int type(int x){
	if(cnt[x]==2)return x==5||x==10?0:2;
	return cnt[x];
}
int p(int x,int y){
	return(x-1)*m+y;
}
int p(int x,int y,int f){
	f&=3;
	if(f==0)return(x-1)*m+y+n*m;
	if(f==1)return(x-1)*(m+1)+y+1+n*m+(n+1)*m;
	if(f==2)return x*m+y+n*m;
	return(x-1)*(m+1)+y+n*m+(n+1)*m;
}
void gao(int a,int b,int c,int d,int f){
	if(f)
		add(a,b,c,d);
	else
		add(b,a,c,d);
}
int main(){
	int i,j,x,s1,s2;
	for(i=1;i<16;i++)cnt[i]=cnt[i>>1]+(i&1);
	rot[2]=1;
	rot[4]=2;
	rot[6]=1;
	rot[8]=3;
	rot[9]=3;
	rot[11]=3;
	rot[12]=2;
	rot[13]=2;
	rot[14]=1;
	scanf("%d%d",&n,&m);
	S=n*m+(n+1)*m+n*(m+1)+1;
	N=T=S+1;
	s1=s2=0;
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			scanf("%d",&x);
			if(x==0)continue;
			if((i+j)&1){
				s1+=cnt[x];
				add(S,p(i,j),inf,0);
			}else{
				s2+=cnt[x];
				add(p(i,j),T,inf,0);
			}
			if(x==5){
				gao(p(i,j),p(i,j,0),1,0,(i+j)&1);
				gao(p(i,j),p(i,j,2),1,0,(i+j)&1);
			}
			if(x==10){
				gao(p(i,j),p(i,j,1),1,0,(i+j)&1);
				gao(p(i,j),p(i,j,3),1,0,(i+j)&1);
			}
			switch(type(x)){
				case 1:
					gao(p(i,j),p(i,j,rot[x]),1,0,(i+j)&1);
					gao(p(i,j,rot[x]),p(i,j,rot[x]+1),1,1,(i+j)&1);
					gao(p(i,j,rot[x]),p(i,j,rot[x]+2),1,2,(i+j)&1);
					gao(p(i,j,rot[x]),p(i,j,rot[x]+3),1,1,(i+j)&1);
					break;
				case 2:
					gao(p(i,j),p(i,j,rot[x]),1,0,(i+j)&1);
					gao(p(i,j),p(i,j,rot[x]+1),1,0,(i+j)&1);
					gao(p(i,j,rot[x]),p(i,j,rot[x]+2),1,1,(i+j)&1);
					gao(p(i,j,rot[x]+1),p(i,j,rot[x]+3),1,1,(i+j)&1);
					break;
				case 3:
					gao(p(i,j),p(i,j,rot[x]),1,0,(i+j)&1);
					gao(p(i,j),p(i,j,rot[x]+1),1,0,(i+j)&1);
					gao(p(i,j),p(i,j,rot[x]+2),1,0,(i+j)&1);
					N++;
					gao(p(i,j,rot[x]),N,1,1,(i+j)&1);
					gao(p(i,j,rot[x]+1),N,1,2,(i+j)&1);
					gao(p(i,j,rot[x]+2),N,1,1,(i+j)&1);
					gao(N,p(i,j,rot[x]+3),1,0,(i+j)&1);
					break;
				case 4:
					gao(p(i,j),p(i,j,0),1,0,(i+j)&1);
					gao(p(i,j),p(i,j,1),1,0,(i+j)&1);
					gao(p(i,j),p(i,j,2),1,0,(i+j)&1);
					gao(p(i,j),p(i,j,3),1,0,(i+j)&1);
					break;
			}
		}
	}
	if(s1!=s2||costflow()!=s1)
		puts("-1");
	else
		printf("%d",cost);
}

[UOJ336]无限之环的更多相关文章

  1. Loj #2321. 「清华集训 2017」无限之环

    Loj #2321. 「清华集训 2017」无限之环 曾经有一款流行的游戏,叫做 *Infinity Loop***,先来简单的介绍一下这个游戏: 游戏在一个 \(n \times m\) 的网格状棋 ...

  2. Noip模拟63 2021.9.27(考场惊现无限之环)

    T1 电压机制 把题目转化为找那些边只被奇数环包含. 这样的话直接$dfs$生成一棵树,给每个点附上一个深度,根据其他的非树边都是返祖边 可以算出环内边的数量$dep[x]-dep[y]+1$,然后判 ...

  3. 【uoj336】【清华集训2017】无限之环

    题目 描述 ​ 给出一个\(n*m\)的网格,每个格子里的水管可能向四个方向都有接口: ​ 游戏的目的是不能让水管漏水,即所有接口都有另一个接口与之相接: ​ 你一步可以将一个格子中的水管旋转\(90 ...

  4. 洛谷P4003 无限之环(infinityloop)(网络流,费用流)

    洛谷题目传送门 题目 题目描述 曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏: 游戏在一个 n ∗ m 的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在格 ...

  5. BZOJ5120 [2017国家集训队测试]无限之环 费用流

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ5120 题意概括 原题挺简略的. 题解 本题好难. 听了任轩笛大佬<国家队神犇>的讲课才 ...

  6. BZOJ.5120.[清华集训2017]无限之环(费用流zkw 黑白染色)

    题目链接 LOJ 洛谷 容易想到最小费用最大流分配度数. 因为水管形态固定,每个点还是要拆成4个点,分别当前格子表示向上右下左方向. 然后能比较容易地得到每种状态向其它状态转移的费用(比如原向上的可以 ...

  7. BZOJ5120 无限之环(费用流)

    方案合法相当于要求接口之间配对,黑白染色一波,考虑网络流.有一个很奇怪的限制是不能旋转直线型水管,考虑非直线型水管有什么特殊性,可以发现其接口都是连续的.那么对于旋转水管,可以看做是把顺/逆时针方向上 ...

  8. LOJ2321. 「清华集训 2017」无限之环【费用流】

    LINK 很好的一道网络里题 首先想插头DP的还是出门左转10分代码吧 然后考虑怎么网络流 首先要保证没有漏水 也就是说每个接口一定要有对应的接口 那么发现每个点只有可能和上下左右四个点产生联通关系 ...

  9. bzoj 5120 [2017国家集训队测试]无限之环——网络流

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5120 旋转的话相当于去掉一个插头.新增一个插头,所以在这两个插头之间连边并带上费用即可. 网 ...

随机推荐

  1. 【洛谷 P2783】 有机化学之神偶尔会做作弊 (双联通分量)

    题目链接 可能是除了<概率论>的最水的黑题了吧 用\(Tarjan\)缩点(点双联通分量),然后就是树上两点之间的距离了,跑\(LCA\)就好了. #include <cstdio& ...

  2. PAT L1-009 N个数求和(运用GCD进行通分)

    题目链接:https://www.patest.cn/contests/gplt/L1-009 题目: 本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数“分子/分母”的形式给出的,你 ...

  3. bzoj 1856 组合

    这道题有些类似卡特兰数的其中一种证明,总方案数是c(n+m,n),点(m,n)对应y=x-1对称点为(n+1,m-1),所以答案为c(n+m,n)-c(n+m,n+1). 反思:开始坐标轴画错了,结果 ...

  4. css文本垂直水平居中

    一.单行文本居中 .content{ height:100px; line-height:100px; text-align:center; border:1px solid red; } 效果图 二 ...

  5. Intel MKL(Math Kernel Library)

    1.Intel MKL简介 Intel数学核心函数库(MKL)是一套高度优化.线程安全的数学例程.函数,面向高性能的工程.科学与财务应用.英特尔 MKL 的集群版本包括 ScaLAPACK 与分布式内 ...

  6. PKUWC 2019 自闭记

    PKUWC 2019 自闭记 Day -1 考前天天在隔壁的物竞教室划水(雀魂,能和吉老师一起玩的游戏都是好游戏),没有做题. Day 0 早上8:16的高铁,到广州南居然要6个小时...不知道福州和 ...

  7. ioctl( ) 函数

    ioctl( )函数 本函数影响由fd参数引用的一个打开的文件. #include<unistd.h> int ioctl( int fd, int request, .../* void ...

  8. 【转】C++多继承的细节

    这几天写的程序应用到多继承. 以前对多继承的概念非常清晰,可是很久没用就有点模糊了.重新研究一下,“刷新”下记忆. 假设我们有下面的代码: #include <stdio.h> class ...

  9. nvidia tk1使用记录--基本环境搭建

    前言 项目最开始是在X86+Nvidia(ubuntu+opencv+cuda)平台上实现,达到了期望性能,最近考虑将其移植到嵌入式平台,特别是最近nvidia出了tegra X1,基于和我们使用的g ...

  10. 64_a1

    AGReader-1.2-16.fc26.x86_64.rpm 13-Feb-2017 23:31 50654 ATpy-0.9.7-11.fc26.noarch.rpm 13-Feb-2017 22 ...