洛谷P8281 「MCOI-08」Fast Enumeration
求所有哈密顿回路,这玩意是个 $ O(n!) $ 啊,有点吓人。
注意到一条特殊性质:
对于一条哈密顿回路,每一个点的入度与出度都为 $ 1 $。
有了这一条性质,我们可以直接马上立刻把问题转化为一个精确覆盖问题,并使用舞蹈链(Dancing Links X)解决掉。
什么,你还不会舞蹈链,建议看一下其他大佬的博客。
或者我的也行(逃。
模型构建:
每一行为一条边 $ (x,y) $,插入两个点 $ (i,x) $ 与 $ (i,y+n) $,分别表示 $ x $ 只能入度为 $ 1 \(,\) y $ 只能出度为 $ 1 $。
在舞蹈链上面跑出要选择的边,在统计所有答案就行啦!吗?最后一点,这样跑出来的方案只能保证入度出度为 $ 1 $,所以有可能是几个环而不是一个,验证一下即可。
时间复杂度:玄学,一共大概有 $ n^2 $ 条边,$ O(C{2n2})(C \approx 1) $,能过, 因为舞蹈链 nb。
空间复杂度:$ O(n^2) $。
上代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n, m, id, ans;
int L[N], R[N], U[N], D[N], first[N], rec[N];
int colcnt[N], col[N], row[N];
struct node {
int x, y;
}dat[N]; //边的记录
inline void build(int c) {
for (int i = 0; i <= c; i++) {
L[i] = i - 1, R[i] = i + 1;
U[i] = i, D[i] = i;
}
L[0] = c, R[c] = 0, id = c + 1;
}
inline void remove(int x) {
R[L[x]] = R[x], L[R[x]] = L[x];
for (int y = U[x]; y != x; y = U[y]) {
for (int z = R[y]; z != y; z = R[z]) {
U[D[z]] = U[z], D[U[z]] = D[z];
colcnt[col[z]]--;
}
}
}
inline void recover(int x) {
R[L[x]] = x, L[R[x]] = x;
for (int y = U[x]; y != x; y = U[y]) {
for (int z = R[y]; z != y; z = R[z]) {
U[D[z]] = z, D[U[z]] = z;
colcnt[col[z]]++;
}
}
}
inline void insert(int r, int c) {
id++;
row[id] = r, col[id] = c;
colcnt[c]++;
U[id] = c, D[id] = D[c], U[D[c]] = id, D[c] = id;
if (!first[r]) first[r] = L[id] = R[id] = id;
else {
L[id] = first[r], R[id] = R[first[r]];
L[R[first[r]]] = id, R[first[r]] = id;
}
}
int nxt[60], resnum, vis[60]; //vis别开大啦,不然会TLE
std::vector<int> res[N];
inline void dance(int depth) {
if (!R[0]) {
memset(vis, 0, sizeof vis);
for (int i = 0; i < depth; i++) nxt[dat[rec[i]].x] = dat[rec[i]].y;
for (int now = 1; !vis[now]; now = nxt[now]) vis[now] = 1;
for (int i = 1; i <= n; i++) if (!vis[i]) return; //验证是否为一个环
res[++resnum].push_back(1);
for (int i = nxt[1]; i != 1; i = nxt[i]) res[resnum].push_back(i);
return;
}
int y = R[0];
for (int i = R[0]; i; i = R[i]) {
if (colcnt[i] < colcnt[y]) y = i;
}
remove(y);
for (int i = D[y]; i != y; i = D[i]) {
rec[depth] = row[i];
for (int j = R[i]; j != i; j = R[j]) remove(col[j]);
dance(depth + 1);
for (int j = L[i]; j != i; j = L[j]) recover(col[j]);
}
recover(y);
}
inline bool cmp(std::vector<int> x, std::vector<int> y) {
for (int i = 1; i < n; i++) {
if (x[i] == y[i]) continue;
return x[i] < y[i];
}
}
int main() {
cin >> n >> m;
build(n * 2);
for (int i = 1; i <= m; i++) {
cin >> dat[i].x >> dat[i].y;
insert(i, dat[i].x), insert(i, dat[i].y + n);
}
dance(0);
sort(res + 1, res + resnum + 1, cmp);
for (int i = 1; i <= resnum; i++) {
for (int j = 0; j < n; j++) cout << res[i][j] << ' ';
cout << '\n';
}
return 0;
}

浙公网安备 33010602011771号