Hướng giải của Lights Out
Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Tác giả:
Lời giải: Lights Out
Phân tích
Mỗi ô trên lưới là một ẩn (bấm hoặc không). Mỗi ô cho một phương trình trên GF(2): trạng thái cuối = trạng thái đầu XOR (tổng các ô được bấm ảnh hưởng đến nó). Giải hệ \(n imes m\) phương trình bằng Gauss trên GF(2).
Độ phức tạp: \(O((nm)^3)\), với \(n,m \le 10\) thì đủ nhanh.
Code mẫu C++
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int N = n * m; // So an = so o
// Ma tran mo rong [A | b] tren GF(2)
vector<vector<int>> a(N, vector<int>(N + 1, 0));
// Huong di chuyen: o hien tai va 4 o ke
int dx[] = {0, 0, 0, 1, -1};
int dy[] = {0, 1, -1, 0, 0};
// Doc trang thai ban dau (ve phai b)
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int idx = i * m + j; // Chi so cua o (i,j)
cin >> a[idx][N]; // Ve phai = trang thai hien tai
// O (i,j) bi anh huong boi chinh no va 4 o lan can
for (int d = 0; d < 5; d++) {
int ni = i + dx[d];
int nj = j + dy[d];
if (ni >= 0 && ni < n && nj >= 0 && nj < m) {
a[idx][ni * m + nj] = 1;
}
}
}
}
// Gauss tren GF(2): khu dan tung cot
for (int i = 0; i < N; i++) {
// Tim hang co phan tu khac 0 tai cot i
int p = i;
while (p < N && a[p][i] == 0) p++;
if (p == N) {
// Vo nghiem
cout << -1 << endl;
return 0;
}
// Doi hang p len vi tri i
swap(a[i], a[p]);
// Khu cot i o tat ca cac hang khac (tren GF(2): XOR)
for (int j = 0; j < N; j++) {
if (j != i && a[j][i] == 1) {
for (int k = i; k <= N; k++) {
a[j][k] ^= a[i][k];
}
}
}
}
// In ket qua: nhung o co gia tri 1 la can bam
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i * m + j][N] == 1) {
cout << i + 1 << " " << j + 1 << endl;
}
}
}
return 0;
}
Nhận xét