求超立方体的哈密顿路径
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;
}

浙公网安备 33010602011771号