สังเกตว่าสิ่งที่เราสนใจจริง ๆ ไม่ใช่สถานะเริ่มต้นหรือสถานะสิ้นสุดของหลอดไฟ แต่เป็นการเปลี่ยนแปลงสถานะของหลอดไฟ ดังนั้น เพื่อความสะดวก จะนิยามให้ สื่อถึงการเปลี่ยนแปลงสถานะของหลอดไฟในแถวที่ หลักที่ (สำหรับ ) โดยถ้าต้องมีการเปลี่ยนสถานะจากปิดเป็นเปิดหรือจากเปิดเป็นปิด จะได้ มิเช่นนั้นจะได้
สำหรับแต่ละปุ่ม เมื่อกดปุ่มมากกว่า 1 ครั้ง ผลที่เกิดต่อหลอดไฟดวงนั้นและหลอดไฟดวงข้าง ๆ จะเทียบเท่ากับการไม่กดปุ่มเลย (ถ้ากดเป็นจำนวนคู่ครั้ง) หรือการกดปุ่มเพียง 1 ครั้ง (ถ้ากดเป็นจำนวนคี่ครั้ง) ดังนั้น เราจะพิจารณากดปุ่มแต่ละปุ่มแค่ 0 หรือ 1 ครั้งเท่านั้น เพื่อความสะดวก นิยามให้ เมื่อเลือกไม่กดปุ่มในแถวที่ หลักที่ และ เมื่อเลือกกดปุ่ม
สังเกตว่าการเปลี่ยนแปลงสถานะของหลอดไฟแถวที่ หลักที่ เกิดจากจำนวนครั้งที่ปุ่มของหลอดไฟนั้นหรือปุ่มข้าง ๆ ถูกกด โดยถ้าถูกกดเป็นจำนวนคี่ครั้งจะมีการเปลี่ยนแปลงสถานะเกิดขึ้น แต่ถ้าถูกกดเป็นจำนวนคู่ครั้งจะไม่มีการเปลี่ยนแปลง
เช่น หากพิจารณา , จะได้ความสัมพันธ์เป็น
หากเราพิจารณาความสัมพันธ์ของการเปลี่ยนแปลงสถานะกับการกดปุ่มสำหรับหลอดไฟทุกดวง จะได้สมการเชิงเส้นทั้งหมด สมการ เนื่องจากโจทย์กำหนดค่า ให้อยู่แล้ว เราสามารถแก้สมการหาค่า ต่าง ๆ ใน modulo 2 ได้ แล้วตอบทุก ที่ทำให้
เราสามารถแก้สมการเชิงเส้นได้ด้วย Gauss–Jordan elimination โดยเพื่อความสะดวกในการสร้างเมทริกซ์สัมประสิทธิ์และเวกเตอร์คำตอบ ให้แปลงพิกัด ให้กลายเป็นเลข เช่น หาก พิกัด จะถือว่าเป็นตัวแปรลำดับที่
เนื่องจากเรามีทั้งหมด สมการ และมีสัมประสิทธิ์และค่าคำตอบ รวม ตัวต่อสมการ ดังนั้น หากใช้ Gauss–Jordan elimination จะต้องใช้เวลาในการทำงานทั้งหมด และพื้นที่ทั้งหมด
Implementation
ในภาษา C++:
#include <cstdio> #include <algorithm> using namespace std; const int N = 20; int n; int A[N * N][N * N]; int B[N]; int calc(int x, int y) { return (x < 0 || x >= n || y < 0 || y >= n ? -1 : (x)*n + (y)); } void swapRow(int x, int y) { for (int j = 0; j <= n * n; ++j) { swap(A[x][j], A[y][j]); } } void addRow(int from, int to) { for (int j = 0; j <= n * n; ++j) { A[to][j] = (A[to][j] + A[from][j]) % 2; } } int main() { scanf("%d", &n); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { int u = calc(i, j); scanf("%d", &A[u][n * n]); } } for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { int x; scanf("%d", &x); int u = calc(i, j); A[u][n * n] = (A[u][n * n] + x) % 2; } } for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { int u = calc(i, j); int v[] = {u, calc(i - 1, j), calc(i + 1, j), calc(i, j - 1), calc(i, j + 1)}; for (int k = 0; k < 5; ++k) { if (v[k] == -1) v[k] = u; A[v[k]][u] = 1; } } } for (int i = 0; i < n * n; ++i) { for (int j = i; j < n * n; ++j) { if (A[j][i] == 1) { swapRow(i, j); break; } } for (int j = 0; j < n * n; ++j) { if (j == i) continue; if (A[j][i] == 1) addRow(i, j); } } int cnt = 0; for (int i = 0; i < n * n; ++i) { if (A[i][n * n] == 1) ++cnt; } printf("%d\n", cnt); for (int i = 0; i < n * n; ++i) { if (A[i][n * n] == 1) { printf("%d %d\n", i / n + 1, i % n + 1); } } return 0; }