LOJ#2321. 「清华集训 2017」无限之环
? 解题记录 ? ? LOJ ? ? 动态规划 ? ? 轮廓线 ?    2018-02-28 14:52:27    656    0    0

题目描述

曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏:

游戏在一个 n×m 的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在方格某些方向的边界的中点有接口,所有水管的粗细都相同,所以如果两个相邻方格的公共边界的中点都有接头,那么可以看作这两个接头互相连接。水管有以下 15 种形状:

Screen Shot 2017-12-04 at 18.13.48.png Screen Shot 2017-12-04 at 18.13.55.png

游戏开始时,棋盘中水管可能存在漏水的地方。

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

玩家可以进行一种操作:选定一个含有非直线型水管的方格,将其中的水管绕方格中心顺时针或逆时针旋转 909090 度。

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

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

输入格式

第一行两个正整数 n,m,代表网格的大小。

接下来 n 行每行 m 个数,每个数是 [0,15] 中的一个,你可以将其看作一个 4位的二进制数,从低到高每一位分别代表初始局面中这个格子上、右、下、左方向上是否有 水管接头。

特别地,如果这个数是 0,则意味着这个位置没有水管。

比如 3(0011(2)) 代表上和右有接头,也就是一个 L 型,而 12(1100(2)) 代表下和左有接头,也就是将 L 型旋转 180 度。

输出格式

输出共一行,表示最少操作次数。如果无法达成目标,输出 -1.

样例

样例输入 1

2 3
3 14 12
3 11 12

样例输出 1

2

样例输入 2

3 2 
1 8 
5 10 
2 4

样例输出 2

-1

样例输入 3

3 3
9 11 3
13 15 7 
12 14 6

样例输出 3

16​​

 前传:*集训下午*

K404机房里……A14座位:巨佬*1,A12座位:dalao*1,A13:蒟蒻的我。

题目布置下来了……看看T1,嗯?无限之环?目测一下搜索过10,轮廓线40分。不过这100分怎么拿呀QAQ……此时A14、A12大佬已经打起了T1。*窥屏大法*,A14大佬写了一个……额,费用流??愣了10分钟后,意识到这真是个费用流,不过这个连边简直……hhhhh。没办法,那就写16种连边吧QAQ……

 

--3个小时过去了,边还是没连完--

 

临走前问了问A12大佬连边怎么连的

大佬说:我用的轮廓线,因为有一维不会超long long,可以用map记录有效状态,比费用流快10倍……。

我:……mmp。

于是今天终于把这个坑填了!算是map优化轮廓线dp?代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#define LL long long
#define ItMap map<LL, int>::iterator
using namespace std;
const int maxn = 2e3 + 5, inf = 0x3f3f3f3f;
int mp[maxn][maxn], temUL = 9;
int n, m, nans;
LL nowst, stmax, hbit, nblk, lgst, now, k;
map<LL, int> dp[2];

inline int Lrot(int st) {return (st & 1) ? (st >> 1) + 8 : st >> 1;}
inline void Symmetry(int & st) {st = ((st & 2) << 1) | ((st & 4) >> 1) | ((st & 1) << 3) | ((st & 8) >> 3);}

int main() {
	scanf("%d%d", &n, &m);
	if(n <= m) {
		for(register int i = 1; i <= n; ++i)
			for(register int j = 1; j <= m; ++j) 
				scanf("%d", &mp[i][j]);
	} else {
		for(register int i = 1; i <= n; ++i)
			for(register int j = 1; j <= m; ++j) 
				scanf("%d", &mp[j][i]), Symmetry(mp[j][i]);
		swap(n, m);
	}
	stmax = (1ll << n + 1), hbit = 1ll << n;
	dp[0][0] = 0;
	for(register int j = 1; j <= m; ++j)
		for(register int i = 1; i <= n; ++i) {
			now ^= 1;
			dp[now].clear();
			for(register ItMap it = dp[now ^ 1].begin(); it != dp[now ^ 1].end(); ++it) {
				if(it -> second == inf) continue;
				k = it -> first;
				nblk = mp[i][j], nans = dp[now ^ 1][k];
				lgst = (k & 1) + ((k & hbit) != 0) * 8;
				if(!(lgst ^ (nblk & temUL))) {
					nowst = (k << 1) % stmax;
					(nowst >>= 2) <<= 2, nowst |= (nblk & 2) | ((nblk & 4) >> 2);
					//printf("STAY %d -> %d ", k, nowst);
					if(!dp[now].count(nowst)) dp[now][nowst] = nans;
					else dp[now][nowst] = min(dp[now][nowst], nans);
				}
				if(nblk == 5 || nblk == 10) continue;
				nblk = Lrot(nblk);
				if(!(lgst ^ (nblk & temUL))) {
					nowst = (k << 1) % stmax;
					(nowst >>= 2) <<= 2, nowst |= (nblk & 2) | ((nblk & 4) >> 2);
					//printf("LT %d -> %d ", k, nowst);
					if(!dp[now].count(nowst)) dp[now][nowst] = nans + 1;
					else dp[now][nowst] = min(dp[now][nowst], nans + 1);
				}
				nblk = Lrot(nblk);
				if(!(lgst ^ (nblk & temUL))) {
					nowst = (k << 1) % stmax;
					(nowst >>= 2) <<= 2, nowst |= (nblk & 2) | ((nblk & 4) >> 2);
					//printf("OPP %d -> %d ", k, nowst);
					if(!dp[now].count(nowst)) dp[now][nowst] = nans + 2;
					else dp[now][nowst] = min(dp[now][nowst], nans + 2);
				}
				nblk = Lrot(nblk);
				if(!(lgst ^ (nblk & temUL))) {
					nowst = (k << 1) % stmax;
					(nowst >>= 2) <<= 2, nowst |= (nblk & 2) | ((nblk & 4) >> 2);
					//printf("RT %d -> %d ", k, nowst);
					if(!dp[now].count(nowst)) dp[now][nowst] = nans + 1;
					else dp[now][nowst] = min(dp[now][nowst], nans + 1);
				}
			}
			if(i == n) {
				for(ItMap k = dp[now].begin(); k != dp[now].end(); ++k) 
					if(k -> first & 1) k -> second = inf;
			}
			//printf("\n");
		}
	if(dp[now].count(0)) printf("%d", dp[now][0] != inf ? dp[now][0] : -1);
	else printf("-1");
	return 0;
}

 

上一篇: 回文串计数(palindromes)

下一篇: 洛谷P2742 [USACO5.1]圈奶牛Fencing the Cows

656 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航