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.

Tác giả: kienadmin

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

Không có ý kiến tại thời điểm này.