【模板】欧拉回路/路径和哈密尔顿回路

Luogu欧拉回路P7771

关于该题的借鉴

欧拉路就是经过所有的边恰好一次的路径,欧拉回路就是转转完所有边然后还要回到初始结点。

考虑欧拉回路即是所有结点出度等于入度。考虑欧拉路就是除了两个结点,一个结点出-入==1,另一个入-出==1其他出度等于入度。

然后关于欧拉路的做法,按照离散数学就是找出一个环,然后把这个环上的所有边去除掉然后再递归到各自的环上跑欧拉路。对于实现上来说,深搜可以做到这个,就是找出了一个环的同时,递归到各自下面的分支环上。做法就是搜到某个点,跑边,然后删除掉该边,继续跑,在跑完之后再将该点加入栈序列中。最终结果就是栈序列出栈的序列。

#include <bits/stdc++.h>

using namespace std;
const int maxn = 2e5 + 5;
int n, m;
vector<int> ve[maxn];
unordered_set<int> se[maxn];
int rd[maxn], cd[maxn];
int sta[maxn], top;
int ded[maxn];
void dfs(int x) {
    for (int it = ded[x]; it < ve[x].size(); it = ded[x]) {
        ded[x] = it + 1;
        dfs(ve[x][it]);
    }
    sta[++top] = x;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        ve[x].push_back(y);
        cd[x]++, rd[y]++;
    }
    for (int i = 1; i <= n; i++) {
        sort(ve[i].begin(), ve[i].end());
    }
    int qidian = 1;
    int c1 = 0, c2 = 0;
    bool huilu_flag = 1;
    for (int i = 1; i <= n; i++) {
        if (rd[i] != cd[i])
            huilu_flag = 0;
        if (cd[i] - rd[i] == 1)
            c1++, qidian = i;
        if (rd[i] - cd[i] == 1)
            c2++;
        if (rd[i] - cd[i] >= 2 || cd[i] - rd[i] >= 2) {
            puts("No");
            return 0;
        }
    }
    if ((!huilu_flag) && !(c1 == c2 && c1 == 1)) {
        puts("No");
        return 0;
    }
    dfs(qidian);
    for (int i = top; i >= 1; i--) {
        printf("%d ", sta[i]);
    }
}

关于哈密顿回路

目前哈密顿回路是一个NP问题,即可以最坏多项式时间复杂度判断,但是目前是指数级别求。

我们可以通过状态压缩,解决这个问题。具体就是设定f[2^n][n]表示已经经过的点状态+目前在的点。回路就在求到经过恰好所有点一次后再分别判断一下即可。如果没有固定起点,那也就是O(2^n*n^2)解决的问题。总之,状态压缩是关键。

posted @ 2022-04-08 13:43  Newuser233  阅读(228)  评论(0编辑  收藏  举报