[BZOJ5120] [2017国家集训队测试]无限之环
Description
曾经有一款流行的游戏,叫做InfinityLoop,先来简单的介绍一下这个游戏:
游戏在一个n×m的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在方格某些方向的边界的中点有接口
,所有水管的粗细都相同,所以如果两个相邻方格的公共边界的中点都有接头,那么可以看作这两个接头互相连接
。水管有以下15种形状:

游戏开始时,棋盘中水管可能存在漏水的地方。
形式化地:如果存在某个接头,没有和其它接头相连接,那么它就是一个漏水的地方。
玩家可以进行一种操作:选定一个含有非直线型水管的方格,将其中的水管绕方格中心顺时针或逆时针旋转90度。
直线型水管是指左图里中间一行的两种水管。
现给出一个初始局面,请问最少进行多少次操作可以使棋盘上不存在漏水的地方。
Input
第一行两个正整数n,m代表网格的大小。
接下来n行每行m数,每个数是[0,15]中的一个
你可以将其看作一个4位的二进制数,从低到高每一位分别代表初始局面中这个格子上、右、下、左方向上是否有水管接头。
特别地,如果这个数是000,则意味着这个位置没有水管。
比如3(0011(2))代表上和右有接头,也就是一个L型,而12(1100(2))代表下和左有接头,也就是将L型旋转180度。
n×m≤2000
Output
输出共一行,表示最少操作次数。如果无法达成目标,输出-1
Sample Input
2 3
3 14 12
3 11 12
Sample Output
2
Solution
这是个什么鬼题嘛....
思路不是很复杂,考虑网络流,每个点拆成五个,上下左右各一个,中间一个,设为\(P_{x,0..4}\)。
对网格图进行黑白染色,对于黑点,源点\(s\)向\(P_{x,0}\)连边;对于白点,\(P_{x,0}\)向\(t\)连边,容量\(+\infty\),费用\(0\)。
对于相邻的两个点,我们设黑点为发射点,白点为接收点,那么黑点另外四个点向相应的四周的点连边,比如说\(u=(x,y),v=(x+1,y)\),且\(u\)为黑点,那么我们可以连边\(P_{u,2} \to P_{v,4}\);若\(u\)为白点就连边\(P_{v,4}\to P_{u,2}\)。其中容量为\(1\),费用为\(0\)。
那么一个基本的框架就构造完成了,现在考虑如何旋转。
- 首先,对于任意一个图形,不考虑旋转,那么中心点向对应点连边,容量\(1\),费用\(0\)。
- 若当前点为直线或者没有,直接不管就好了。
- 设当前点的形状为\(x\),设\(t=bit\_cnt(x)\)表示当前点有几个连出去的边,那么可以分情况讨论:
- \(t=1\),向相邻方向连容量为\(1\),费用为\(1\)的边,向对面方向连费用\(2\)的边。
- \(t=2\),对于每个方向向对面方向连费用为\(1\),容量为\(1\)的边。
- \(t=3\),其实和\(t=1\)的情况差不多,相当于是反向连边,缺口那个方向相邻的向缺口连费用\(1\)的,相对的连费用为\(2\)的。
- 其实质上就相当于是每次旋转都只会移动一个方向,顺着这个思路画画图连边就好了,这也是为啥题目要规定直线不能转,因为直线转了就会有两个方向的改变。
然后这题就做完了,代码及其恶心...
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 2e5+10;
const int inf = 1e9;
int s,t,n,m,tot=1,cost,flow,sum;
int dis[maxn],vis[maxn],head[maxn],mp[maxn];
struct edge{int to,nxt,w,c;}e[maxn];
// emmm
int bfs() {
memset(dis,63,(t+1)*4);
memset(vis,0,(t+1)*4);
queue<int > q;q.push(s);dis[s]=0,vis[s]=1;
while(!q.empty()) {
int x=q.front();q.pop();vis[x]=0;
for(int i=head[x],v;i;i=e[i].nxt)
if(e[i].w>0&&dis[v=e[i].to]>dis[x]+e[i].c) {
dis[v]=dis[x]+e[i].c;
if(!vis[v]) q.push(v),vis[v]=1;
}
}return dis[t]<inf;
}
int dfs(int x,int f) {
vis[x]=1;
if(x==t) return cost+=f*dis[t],f;
int used=0;
for(int v,i=head[x];i;i=e[i].nxt)
if(e[i].w>0&&(!vis[v=e[i].to]||v==t)&&dis[v]==dis[x]+e[i].c) {
int d=dfs(e[i].to,min(f-used,e[i].w));
if(d>0) e[i].w-=d,e[i^1].w+=d,used+=d;
if(used==f) break;
}
return used;
}
int mcmf() {
while(bfs()) flow+=dfs(s,inf);return cost;
}
// ---------
void add(int u,int v,int w,int c) {e[++tot]=(edge){v,head[u],w,c},head[u]=tot;}
void ins(int u,int v,int w,int c,int bo) {if(!bo) swap(u,v);add(u,v,w,c),add(v,u,0,-c);}
int p(int x,int y,int tt) {return (x-1)*m+y+tt*n*m;}
const int dk[] = {0,2,1,4,3};
int main() {
read(n),read(m);s=n*m*5+1,t=s+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if((i+j)&1) ins(s,p(i,j,0),inf,0,1);
else ins(p(i,j,0),t,inf,0,1);
for(int i=1,x;i<=n;i++)
for(int j=1;j<=m;j++) {
if((i+j)&1) {
if(i>1) ins(p(i,j,2),p(i-1,j,4),1,0,1);
if(j>1) ins(p(i,j,3),p(i,j-1,1),1,0,1);
if(i<n) ins(p(i,j,4),p(i+1,j,2),1,0,1);
if(j<m) ins(p(i,j,1),p(i,j+1,3),1,0,1);
}
read(x);int bo=(i+j)&1;
int bit=__builtin_popcount(x),tt=1;
sum+=bit;
if(!x) continue;
if(x==5||x==10) {
for(int k=1;k<=4;k++)
if(x>>(k-1)&1) ins(p(i,j,0),p(i,j,dk[k]),1,0,bo);
continue;
}
if(bit==1) {
if(x==1) tt=2;else if(x==8) tt=3;else if(x==4) tt=4;
for(int k=1;k<=4;k++)
ins(p(i,j,tt),p(i,j,(tt+k+3)%4+1),1,min(k,4-k),bo);
} else if(bit==2) {
int a=0,b;
for(int k=1;k<=4;k++)
if((x>>(k-1))&1)
{if(!a) a=dk[k];else b=dk[k];}
ins(p(i,j,a),p(i,j,(a+5)%4+1),1,1,bo);
ins(p(i,j,b),p(i,j,(b+5)%4+1),1,1,bo);
} else if(bit==3) {
int mid,l;
if(x==11) mid=2;
else if(x==13) mid=3;
else if(x==14) mid=4;
else mid=1;l=(mid+5)%4+1;
for(int k=1;k<=4;k++)
if((x>>(k-1))&1) {
ins(p(i,j,dk[k]),p(i,j,l),1,dk[k]==mid?2:1,bo);
}
}
for(int k=1;k<=4;k++)
if(x>>(k-1)&1) ins(p(i,j,0),p(i,j,dk[k]),1,0,bo);
}
mcmf();
if((flow<<1)==sum) write(cost);else puts("-1");
return 0;
}
[BZOJ5120] [2017国家集训队测试]无限之环的更多相关文章
- BZOJ5120 [2017国家集训队测试]无限之环 费用流
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ5120 题意概括 原题挺简略的. 题解 本题好难. 听了任轩笛大佬<国家队神犇>的讲课才 ...
- bzoj 5120 [2017国家集训队测试]无限之环——网络流
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5120 旋转的话相当于去掉一个插头.新增一个插头,所以在这两个插头之间连边并带上费用即可. 网 ...
- bzoj 5120: [2017国家集训队测试]无限之环【最小费用最大流】
玄妙的建图-- 这种平衡度数的题按套路是先黑白染色然后分别连ST点,相邻格子连黑向白连费用1流量0的边,然后考虑费用怎么表示 把一个点拆成五个,上下左右中,中间点黑白染色连ST, 对于连S的点,中点连 ...
- BZOJ 5120: [2017国家集训队测试]无限之环(费用流)
传送门 解题思路 神仙题.调了一个晚上+半个上午..这道咋看咋都不像图论的题竟然用费用流做,将行+列为奇数的点和偶数的点分开,也就是匹配问题,然后把一个点复制四份,分别代表这个点的上下左右接头,如果有 ...
- BZOJ_2622_[2012国家集训队测试]深入虎穴_最短路
BZOJ_2622_[2012国家集训队测试]深入虎穴_最短路 Description 虎是中国传统文化中一个独特的意象.我们既会把老虎的形象用到喜庆的节日装饰画上,也可能把它视作一种邪恶的可怕的动物 ...
- 【BZOJ2622】[2012国家集训队测试]深入虎穴 次短路
[BZOJ2622][2012国家集训队测试]深入虎穴 Description 虎是中国传统文化中一个独特的意象.我们既会把老虎的形象用到喜庆的节日装饰画上,也可能把它视作一种邪恶的可怕的动物,例如“ ...
- 2017国家集训队作业Atcoder题目试做
2017国家集训队作业Atcoder题目试做 虽然远没有达到这个水平,但是据说Atcoder思维难度大,代码难度小,适合我这种不会打字的选手,所以试着做一做 不知道能做几题啊 在完全自己做出来的题前面 ...
- 2017国家集训队作业[agc016b]Color Hats
2017国家集训队作业[agc016b]Color Hats 题意: 有\(N\)个人,每个人有一顶帽子.帽子有不同的颜色.现在,每个人都告诉你,他看到的所有其它人的帽子共有多少种颜色,问有没有符合所 ...
- 2017国家集训队作业[agc016e]Poor Turkey
2017国家集训队作业[agc016e]Poor Turkey 题意: 一开始有\(N\)只鸡是活着的,有\(M\)个时刻,每个时刻有两个数\(X_i,Y_i\),表示在第\(i\)个时刻在\(X_i ...
随机推荐
- spring源码-bean之初始化-1
一.spring的IOC控制反转:控制反转——Spring通过一种称作控制反转(IOC)的技术促进了松耦合.当应用了IOC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查 ...
- nio之netty5应用
1.netty5和netty4的区别不是很大,但是与netty3差别还是有的.这里不介绍netty4,因为和netty5的方式都差不多.netty5的复杂性相对于netty3要多很多了.基本上架构都被 ...
- Appium(Python)测试混血App
Hybrid App(混合模式移动应用)是指介于web-app.native-app这两者之间的app兼具Native App良好用户交互体验的优势和Web App跨平台开发的优势 HybridApp ...
- 即刻开始使用Kotlin开发Android的12个原因(KAD 30)
作者:Antonio Leiva 时间:Jul, 11, 2017 原文链接:https://antonioleiva.com/reasons-kotlin-android/ 这组文章已到最后了,它们 ...
- Web自动化selenium技术快速实现爬虫
selenium是大家众所周知的web自动化测试框架,主要用来完成web网站项目的自动化测试,但其实如果要实现一个web爬虫,去某些网站爬取数据,其实用selenium来实现也很方便. 比如,我们现在 ...
- window上小而美的软件(推荐度按排名)
window上小而美的软件,推荐度按排名 Notepad++ 更好用更强大的笔记本 QTranslate 本地翻译神器 7-zip 解压缩软件 Wox 程序/文件/快捷 神器 1! Everthing ...
- 定时任务 linux crontab 学习整理
1. 定时任务命令概念 crontab命令用于设置周期性被执行的指令.即设定脚本 按照规定时间执行相关的操作. 2.定时任务书写规范 * * * ...
- 浅谈PCA
最近在回顾PCA方面的知识,发现对于之前的很多东西有了新的理解,下面和大家分享下我的一些个人的理解 1.我们为什么要用PCA,它能解决我什么问题? PCA(Principal Component An ...
- Python基础简介
一.目前各种语言的应用:java, 可以把特别小的项目做大,并且开源库比较多,C: 用在最底层,例如编写操作系统,运行速率快,开发效率低,C++:常坐游戏引擎Python:AI(人工智能) 简单.明确 ...
- var,let,const,三种申明变量的整理
javascript,正在慢慢变成一个工业级语言,势力慢慢渗透ios,安卓,后台 首先let,是局部变量,块级作用域:var全局的,const是常量,也就是只读的: 一行demo说明 for (var ...