SGU122 The book

SGU122 The book

题目大意

给出一张N个点的无向图,每个点的度数至少为 N+12 ,找出一条哈密顿回路

算法思路

Ore性质: u,vV ,如果 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值