1. 程式人生 > 其它 >【模板】歐拉回路/路徑和哈密爾頓迴路

【模板】歐拉回路/路徑和哈密爾頓迴路

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)解決的問題。總之,狀態壓縮是關鍵。