a243. 第四題:點燈遊戲

contents

  1. 1. Problem
  2. 2. Sample Input
  3. 3. Sample Output
  4. 4. Solution

Problem

點燈遊戲,在二維地圖上,點擊一個燈泡後,亮會變暗、暗會變亮,還有周圍的燈泡也會改變狀態。滿足 $| x1 − x2 | + | y1 − y2 | = d$ 的位置的燈泡也會隨之變化,注意到是曼哈頓距離等於,而非小於等於。

給一個初始盤面,請問點燈結果有沒有解。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1 1 1
1
2 2 1
1 1
1 1
3 2 1
1 0 1
0 1 0
3 3 1
1 0 1
0 1 0
1 0 1
4 4 2
1 1 0 1
0 0 0 1
1 0 1 1
1 0 0 0
5 5 1
1 1 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
5 5 2
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
11 11 3
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
11 11 3
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
13 13 7
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0

Sample Output

1
2
3
4
5
6
7
8
9
10
1
1
0
1
0
0
1
1
0
1

Solution

轉換成聯立方程組,當盤面是 $N \times M$,則用 $N \times M$ 個變數和 $N \times M$ 等式進行解方程。燈泡變換只有 1 -> 00 -> 1,利用高斯消去法解聯立時需要使用 XOR 取代原本的加減乘除計算。變數 $x(i, j) = 1$ 表示要 $(i, j)$ 按下,反之 0 表示不按,最後再模擬一次看能不能翻回全暗。

關於列方程式,下面是一個 $(2, 2)$ 位置被點開的影響周圍情況

1
2
3
4
0100
1110
0100
0000

相同地,周圍也可以影響到自己,那麼方程式就是 $x(1, 2) + x(2, 1) + x(2, 2) + x(2, 3) + x(3, 2) = L(2, 2)$。其中 + 號相當於 XOR 計算,而 L(i, j) 表示初始盤面狀態,當左式等於右式相當於 L(i, j) 被點暗。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <bits/stdc++.h>
using namespace std;
class XOR_GAUSSIAN { // XOR Gaussian Elimination
public:
static const int MAXN = 700;
char mtx[MAXN][MAXN+1], varX[MAXN];
int n;
void compute() {
int row = 0, col = 0, arb = 0;
int equ = n, var = n;
while (row < equ && col < var) {
int c = row;
for (int i = row; i < equ; i++)
if (mtx[i][col])
c = i;
for (int i = 0; i <= var; i++)
swap(mtx[c][i], mtx[row][i]);
if (mtx[row][col] == 0) {
col++, arb++;
continue;
}
for (int i = 0; i < equ; i++) {
if (i == row || mtx[i][col] == 0) continue;
for (int j = var; j >= 0; j--)
mtx[i][j] ^= mtx[row][j];
}
row++, col++;
}
memset(varX, 0, sizeof(varX));
for (int i = 0, j; i < equ; i++) {
if (mtx[i][var] == 0)
continue;
for (j = 0; j < var && mtx[i][j] == 0; j++);
varX[j] = mtx[i][var];
}
}
void init(int n) {
this->n = n;
for (int i = 0; i < n; i++)
for (int j = 0; j <= n; j++)
mtx[i][j] = 0;
}
} gauss;
int main() {
int n, m, d;
int g[32][32];
int cases = 0;
while (scanf("%d %d %d", &m, &n, &d) == 3 && n) {
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
scanf("%d", &g[i][j]);
int N = n*m;
gauss.init(N);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int x = i*m + j, tx, ty;
gauss.mtx[x][N] = g[i][j];
gauss.mtx[x][x] = 1;
for (int dx = -d; dx <= d; dx++) {
int v = d - abs(dx);
int dy[2] = {-v, v}, dn = v == 0 ? 1 : 2;
for (int k = 0; k < dn; k++) {
tx = i + dx, ty = j + dy[k];
if (tx < 0 || ty < 0 || tx >= n || ty >= m)
continue;
gauss.mtx[x][tx*m+ty] = 1;
}
}
}
}
gauss.compute();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (gauss.varX[i*m+j] == 0)
continue;
g[i][j] ^= 1;
int tx, ty;
for (int dx = -d; dx <= d; dx++) {
int v = d - abs(dx);
int dy[2] = {-v, v}, dn = v == 0 ? 1 : 2;
for (int k = 0; k < dn; k++) {
tx = i + dx, ty = j + dy[k];
if (tx < 0 || ty < 0 || tx >= n || ty >= m)
continue;
g[tx][ty] ^= 1;
}
}
}
}
int ok = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
ok &= g[i][j] == 0;
}
}
printf("%d\n", ok);
}
return 0;
}
/*
2 3 1
1 0 1 0 0 0
3 3 2
1 0 0
0 0 0
0 0 0
*/