SGU122 The book
题目大意
给出一张N个点的无向图,每个点的度数至少为 ⌊N+12⌋ ,找出一条哈密顿回路
算法思路
Ore性质:
∀u,v∈V
,如果
deg(u)+deg(v)≥N
,则图中一定存在哈密顿回路
可以用下面的方式构造路径:
- 先构造一条最长链s -> t,使得两个方向都无法继续延伸
- 如果无法成环,则找出一个链上相邻的两个节点u -> v,满足u和t连通,v和s连通
– 将链更新为环:s -> u -> t -> v -> s - 如果当前环长度为n,则返回
- 否则找一个不在环上的点v,在环上找一个点u,满足u和v连通
– 将环更新为链:(s = next[u]) -> u -> (t = v)
– 回到第二步
具体的证明可以参照《组合数学》
时间复杂度: O(N2)
代码
/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: 122.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-05-31
*/
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 1000 + 5;
class Hamilton {
int n, next[maxn];
bool g[maxn][maxn], vis[maxn];
int find(int u)
{
for (int v = 0; v < n; ++v)
if (g[u][v] && !vis[v]) return v;
return -1;
}
void reverse(int v, int f)
{
if (v == -1) return;
reverse(next[v], v); next[v] = f;
}
public:
void init(int n)
{
this->n = n;
memset(g, false, sizeof(g));
}
void add_edge(int u, int v) { g[u][v] = true; }
void find_path(int s = 0)
{
int t = s, sz = 1;
memset(next, -1, sizeof(next));
memset(vis, false, sizeof(vis)); vis[s] = true;
while (sz < n) {
if (sz == 1) {
for (int v; ~(v = find(s)); s = v)
++sz, vis[v] = true, next[v] = s;
for (int v; ~(v = find(t)); t = v)
++sz, vis[v] = true, next[t] = v;
} else {
for (int u, v = 0; v < n; ++v) if (!vis[v]) {
++sz, vis[v] = true;
for (u = s; !g[u][v]; u = next[u]);
s = next[u]; t = next[u] = v; break;
}
}
if (g[t][s]) next[t] = s;
for (int u = next[s], v; next[t] == -1; u = next[u])
if (g[u][t] && g[v=next[u]][s])
reverse(v, s), next[u] = t, t = v;
}
for (int i = 0, u = 0; i < n; ++i, u = next[u])
printf("%d ", u + 1);
printf("%d\n", 1);
}
} grp;
bool get_int(int &v, char* &p)
{
v = 0;
while (*p && !isdigit(*p)) ++p;
if (!isdigit(*p)) return false;
while (isdigit(*p)) v = v * 10 + *p++ - '0';
return true;
}
int main()
{
int n;
scanf("%d\n", &n);
grp.init(n);
rep(u,n) {
int v;
char buf[10000], *p;
gets(buf); p = buf;
while (get_int(v, p)) grp.add_edge(u, --v);
}
grp.find_path();
return 0;
}