无限之环
题目
链接
描述
曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏:
游戏在一个 n ∗ m 的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在
格某些方向的边界的中点有接口,所有水管的粗细都相同,所以如果两个相邻方格的
共边界的中点都有接头,那么可以看作这两个接头互相连接。水管有以下 15 种形状:
游戏开始时,棋盘中水管可能存在漏水的地方。
形式化地:如果存在某个接头,没有和其它接头相连接,那么它就是一个漏水的
地方。
玩家可以进行一种操作:选定一个含有非直线型水管的方格,将其中的水管绕方格
中心顺时针或逆时针旋转 90 度。
直线型水管是指左图里中间一行的两种水管。
现给出一个初始局面,请问最少进行多少次操作可以使棋盘上不存在漏水的地方。
输入格式
从文件 infinityloop.in 中读入数据。
第一行两个正整数 n, m,代表网格的大小。
接下来 n 行每行 m 个数,每个数是 [0,15] 中的一个,你可以将其看作一个 4 位的
二进制数,从低到高每一位分别代表初始局面中这个格子上、右、下、左方向上是否有
水管接头。
特别地,如果这个数是 0 ,则意味着这个位置没有水管。
比如 3(0011(2)) 代表上和右有接头,也就是一个 L 型,而 12(1100(2)) 代表下和左
有接头,也就是将 L 型旋转 180 度。
输出格式
输出到文件 infinityloop.out 中。
输出共一行,表示最少操作次数。如果无法达成目标,输出-1.
子任务
解题法
评价:神奇的网络流神题
出这种题的dalao,%%%
Round 1:黑白染色
对于一个方格,黑白染色后,就分成了两个部分,并且保证同色之间不连边。对于一个格子,需要连接的就是上下左右,全部与原方格异色。
Round 2:方格->网络流的边
拆点,建图。
这道题的精髓就体现在建图。
(未经说明的边均与S或T相连)
单头型
四条边分别是:
- 向上,容量1,费用0。
- 向左右,容量1,费用1。
- 向下,容量1,费用2。
直线型(不能动)
以上下(编号5)为例,建的边有:
- 向上下,容量1,费用0。
弯弯1
要命的就是转来转去怎么办?
顺时针转90°其实相当于把上面那根管子搞到下面来,费用为1。
转180°同理,两根一起调头,费用为2。
于是我们就解决了这么一个问题。
建的边有:
- 向上,容量1,费用0。
- 向右,容量1,费用0。
- 向下与向上相连,容量1,费用1。
- 向左与向右相连,容量1,费用1。
应为容量只有1,所以想要跑出转180°的那种情况费用必须为2.。
(完美!)
弯弯2
以我们的经验,可以秒掉其中三条边:
- 向左右上,容量1,费用0。
仔细一想,发现空的那个地方其实可以由三条边转移而来,
再结合弯弯2型的另外三个图,其实很容易发现剩余边的建法:
- 向左与向下相连,容量1,费用1。
- 向右与向下相连,容量1,费用1。
- 向上与向下相连,容量1,费用2。
十字型
最无脑的。
- 向上下左右,容量1,费用0.。
结束!
至此,我们就完成了建边过程。
至于细枝末节的问题,不再讨论(这不本质)。
Round 3:网络流乱跑!
费用流即可。
代码:
#include<bits/stdc++.h>
#define FN "infinityloop"
const int MN=2000+5;
const int N=8000+5;
const int INF=1e9+7;
namespace LoLiK {
struct Edge {
int v,nxt,cot,fow;
}e[20*N];
int S,T,n,m,id[MN][MN][4];
int h[N],tot=1,cnt=0;
int dx[4]