Loading

【题解】[BalticOI 2010 Day2] Mines

给定一个 \(N\times M\) 的矩阵 \(A\),你需要构造一个 \(0/1\) 矩阵 \(B\),满足 \(A_{i,j}\) 恰好等于它自己和相邻 \(8\) 个位置的 \(B\) 的和。

很适合比赛的一道提交答案题。

我们发现非常类似扫雷游戏,那么我们考虑从一个方向递推过去。

首先枚举左上角四个格子中的数,最多有 \(16\) 种情况,然后枚举第一行和第一列的数,那么剩下的位置可以被我们 \(N\times M\) 递推出来。

直接枚举是 \(2^{N+M}\) 的,\(N,M\) 非常大,这辈子都跑不完,同时这是提交答案题,我们可以考虑各种复杂度是不那么优秀的算法。

我们先写成搜索的构架,然后考虑慢慢优化。包括优化搜索顺序,我们按搜一行然后搜一列的方式交替搜索行和列。对于当前位置不合法及时返回。以及在枚举左上角后,预处理每一行和每一列的起始。

直接跑还是很慢,我们发现将地图旋转或翻转后答案本质不变,所以我们可以将地图转化为 \(8\) 个本质相同的地图,开多个程序同时跑即可。同时观察数据点,可以预处理下哪些行的 \(1\) 多,哪些列的 \(1\) 多。时间最长的点 \(6\) 号点也就跑了 \(5\) 分钟。个人认为 \(6\) 号点时间长是因为 \(N,M\) 的差比较大,并且 \(N,M\)\(\ge 100\)

以下是参考代码,但只用这一份代码是无法跑出所有测试点的。

#define N 605
int n, m, a[N][N], u[N][N], f[N][N]; char ch[N];
int r[N], c[N];
inline bool check(int x,int y,int op){
	if(y > m || (x <= n && x <= y)){
		u[x][1] = op, u[x][2] = r[x] - op;
		if(u[x][2] < 0 || u[x][2] > 1)return false;
		rep(i, 3, y - 1){
			u[x][i] = a[x - 1][i - 1] - f[x - 1][i - 1] - u[x][i - 2] - u[x][i - 1] - u[x - 1][i] - u[x - 2][i];
			if(u[x][i] < 0 || u[x][i] > 1)return false;
			f[x][i] = u[x][i] + u[x][i - 1] + u[x - 1][i] + u[x - 1][i - 1];
			if(x == n && f[x][i] + u[x][i - 2] + u[x - 1][i - 2] != a[x][i - 1])return false;
		}
		if(y > m && f[x][m] + u[x - 2][m] + u[x - 2][m - 1] != a[x - 1][m])return false;
	}
	else{
		u[1][y] = op, u[2][y] = c[y] - op;
		if(u[2][y] < 0 || u[2][y] > 1)return false;
		rep(i, 3, x - 1){
			u[i][y] = a[i - 1][y - 1] - f[i - 1][y - 1] - u[i - 2][y] - u[i - 1][y] - u[i][y - 1] - u[i][y - 2];
			if(u[i][y] < 0 || u[i][y] > 1)return false;
			f[i][y] = u[i][y] + u[i][y - 1] + u[i - 1][y] + u[i - 1][y - 1];
			if(y == m && f[i][y] + u[i - 2][y] + u[i - 2][y - 1] != a[i - 1][y])return false;
		}
		if(x > n && f[n][y] + u[n][y - 2] + u[n - 1][y - 2] != a[n][y - 1])return false;
	}
	return true;
}
void dfs(int x,int y){
	if(x > n && y > m){
		if(f[n][m] == a[n][m]){
			rp(i, n){rp(j, m)if(u[i][j])pc('X'); else pc('.'); el;}
			exit(0);
		}return ;
	}
	if(y > m || (x <= n && x <= y)){
		if(check(x, y, 0))dfs(x + 1, y);
		if(check(x, y, 1))dfs(x + 1, y);
	}
	else{
		if(check(x, y, 0))dfs(x, y + 1);
		if(check(x, y, 1))dfs(x, y + 1);
	}
}
int main() {
	read(n, m);
	rp(i, n){
		scanf("%s", ch + 1);
		rp(j, m)a[i][j] = ch[j] - '0';
	}
	rep(s, 0, 15)if(a[1][1] == __builtin_popcount(s)){
		u[1][1] = s & 1, u[1][2] = (s >> 1) & 1, 
		u[2][1] = (s >> 2) & 1, u[2][2] = (s >> 3) & 1;
		r[1] = u[1][1] + u[1][2], r[2] = u[2][1] + u[2][2];
		c[1] = u[1][1] + u[2][1], c[2] = u[1][2] + u[2][2];
		bool flag = true;
		rep(i, 3, n)r[i] = a[i - 1][1] - (a[i - 2][1] - r[i - 3]), flag &= r[i] >= 0 && r[i] <= 2;
		rep(i, 3, m)c[i] = a[1][i - 1] - (a[1][i - 2] - c[i - 3]), flag &= c[i] >= 0 && c[i] <= 2;
		if(!flag)continue;
		rep(i, 2, n)f[i][2] = r[i] + r[i - 1];
		rep(i, 2, m)f[2][i] = c[i] + c[i - 1];
		if(a[n][1] == f[n][2] && a[1][m] == f[2][m])dfs(3, 3);
	}
	return 0;
}
/*
4 4
2332
3442
3331
3320
1 1 1 0
0 0 0 1
0 1 0 0
1 1 0 0
*/
posted @ 2022-07-21 11:55  7KByte  阅读(50)  评论(0编辑  收藏  举报