求超立方体的哈密顿路径

https://atcoder.jp/contests/agc031/tasks/agc031_c

题意

给定维数 \(n\),起点 \(a\),终点 \(b\),构造 \(a\to b\) 的一条哈密顿路径.

具体来说,给定节点编号 \(0\sim 2^n-1\),每个节点只能与二进制恰好只有一位不同的节点连边.

\(1\le n \le 17\).

思路

首先,相邻节点的 \(popcount\) 奇偶性一定不同,并且 \(popcount\) 为奇和为偶的数量相等,因此 \(popcount(a) \not\equiv popcount(b) \pmod 2\),否则无解.

考虑递归构造,记 \(c\)\(s\)\(t\) 不同的某个二进制位,划分成两部分,左边所有数的第 \(c\) 位都与 \(s\) 相同,右边都与 \(t\) 相同.

此时划分成 \([s\cdots x],[y\cdots t]\),必须满足:

  • 两个区间起点和终点 \(popcount\) 奇偶性不同.

  • 区间内第 \(c\) 位都相同.

  • \(x\)\(y\) 存在边.

因为要递归构造,需要用 \(mask\) 记录哪些位被选中作为划分标准(上文的 \(c\) 构成的集合),\(1\) 表示可用.

\(j\) 为未被占用,且与 \(c\) 不同的某个位,\(x\) 可以取将 \(s\) 的第 \(j\) 位反转得到的数,必然满足 \(popcount(s) \not\equiv popcount(x) \pmod 2\),并且 \(s\)\(x\)\(c\) 位相同. 而 \(y\) 可以取将 \(x\)\(c\) 位反转得到的数.

时间复杂度 \(\mathcal{O}(2^n)\).

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;


void solve(){
    int n,a,b;
    cin >> n >> a >> b;

    if ((__builtin_popcount(a)&1)==(__builtin_popcount(b)&1)){
        cout << "NO" << '\n';
        return;
    }
    cout << "YES" << '\n';

    vector<int> res(1<<n);
    function<void(int,int,int,int,int)> dfs = [&](int mask,int s,int t,int l,int r){
        if (r==l+1){
            res[l] = s;
            res[r] = t;
            return;
        }

        int c = __builtin_ctz((s^t)&mask);
        int nmask = mask^(1<<c);
        int j = __builtin_ctz(nmask);
        int mid = l+r >> 1;
        int x = s^(1<<j);
        int y = x^(1<<c);
        dfs(nmask,s,x,l,mid);
        dfs(nmask,y,t,mid+1,r);
    };
    dfs((1<<n)-1,a,b,0,(1<<n)-1);

    for (int i=1;i<=1<<n;i++){
        cout << res[i] << ' ';
    }
    cout << '\n';
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    // cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-07-25 15:20  kzssCCC  阅读(7)  评论(0)    收藏  举报