Hướng giải của Chuỗi mật mã De Bruijn


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

Đây là bài toán tìm chuỗi De Bruijn. Độ dài ngắn nhất của chuỗi nhị phân De Bruijn cho chiều dài \(K\) là \(2^K + K - 1\). Ta xây dựng đồ thị có hướng gồm \(2^{K-1}\) đỉnh. Mỗi đỉnh là một chuỗi nhị phân độ dài \(K-1\). Từ mỗi đỉnh \(u\) ta có hai cạnh đi ra ứng với việc thêm kí tự 0 hoặc 1 vào cuối, đồng thời loại bỏ kí tự đầu tiên của \(u\). Vì đồ thị này liên thông và bán bậc vào bằng bán bậc ra cho mọi đỉnh, chu trình Euler chắc chắn tồn tại. Ta chạy Hierholzer tìm chu trình này để sinh chuỗi kết quả.

Mã nguồn C++ mẫu
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int k;
    if (!(cin >> k)) return 0;
    if (k == 1) {
        cout << "01\n";
        return 0;
    }
    int num_nodes = 1 << (k - 1);
    vector<vector<pair<int, int>>> adj(num_nodes);
    for (int i = 0; i < num_nodes; i++) {
        int next0 = (i << 1) & (num_nodes - 1);
        int next1 = ((i << 1) | 1) & (num_nodes - 1);
        adj[i].push_back({next0, 0});
        adj[i].push_back({next1, 1});
    }
    vector<int> path;
    stack<int> stk;
    stk.push(0);
    vector<int> ptr(num_nodes, 0);
    while (!stk.empty()) {
        int u = stk.top();
        if (ptr[u] < (int)adj[u].size()) {
            stk.push(adj[u][ptr[u]++].first);
        } else {
            path.push_back(u);
            stk.pop();
        }
    }
    reverse(path.begin(), path.end());
    string ans = "";
    for (int i = 0; i < k - 1; i++) ans += '0';
    for (size_t i = 1; i < path.size(); i++) {
        int u = path[i-1];
        int v = path[i];
        if (v == ((u << 1) & (num_nodes - 1))) {
            ans += '0';
        } else {
            ans += '1';
        }
    }
    cout << ans << "\n";
    return 0;
}

Nhận xét

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