歐拉路徑的判斷與查找

斷定

首先圖必須是聯通的,用並查集判便可c++

無向圖歐拉回路:全部點度數都爲偶數算法

無向圖歐拉路徑:兩個點(或0個點)度數爲奇數,其他點(或全部點)度數爲偶數數組

有向圖歐拉回路:全部點入度=出度spa

有向圖歐拉路徑:一個點入度=出度+1,一個點出度=入度+1,其他點(或全部點)入度=出度.net

查找-Hierholzer算法

//已知存在歐拉路徑,找該路徑
void dfs(int u){//s1~sn中存儲的是歐拉路徑上的點序列
    for(int v=1;v<=n;v++){
        if(mp[u][v]>0){
            mp[u][v]--;
            mp[v][u]--;
            dfs(v);
        }
    }
    s[temp--]=u;
}

爲何是對的?code

由於找歐拉路徑能夠經過在圖上的兩個奇數點之間加一條邊轉化爲求歐拉回路的問題。經過枚舉能夠發現,存在歐拉回路的圖必定是由一些環嵌套而成(能夠經過把一些點一分爲二近似地當作仙人掌圖)遞歸

將一個環當作主環,要一筆畫走完主環,只要在遇到有副環的點u先沿着副環走一圈,再接着沿着主環走就行了ci

Hierholzer算法就是咱們上述思路的一種簡單的實現方法:get

咱們將開始dfs的點屬於的環視爲主環(其實能夠有不少種不一樣的可能性,不必定就是最顯然的那個環),在第一次dfs到沒法遞歸下去時,全部被遍歷到的點都在主環上,顯然應該將最後遍歷到的點放在答案數組的最後,而後一邊回溯,若是仍是沒法遞歸,那接着從後往前存入答案數組,若是能夠遞歸說明這個點上有一個副環,沿着副環遞歸下去,也是一樣的最後遍歷到的點放在後面,這樣子就倒着模擬了咱們以前的算法。it

例題:

The Necklace

https://vjudge.net/contest/347059#problem/C

項鍊的每顆珠子有兩面,每面有一種顏色,項鍊上相鄰兩顆珠子的相鄰面必須是相同的顏色(項鍊是一個環),給定一些珠子和它們的顏色,問可否用盡全部的珠子來組合成一個項鍊?

顏色種類=50

將出現的一種顏色視爲圖上的點,一顆珠子的兩個顏色之間有一條邊,顯然在這樣的圖上若是存在一條歐拉回路,那麼能夠組成項鍊(跑遍全部的邊=用盡全部珠子)。

並查集+Hierholzer算法便可。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
int a[maxn],b[maxn];
int mp[55][55];
int du[55];
int s[maxn],tot,temp;
void dfs(int u){
    for(int v=1;v<=50;v++){
        if(mp[u][v]>0){
            mp[u][v]--;
            mp[v][u]--;
            dfs(v);
        }
    }
    s[temp--]=u;
}
int fa[55],vis[55];
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
int main(){
    int T;
    cin>>T;
    for(int kase=1;kase<=T;kase++){
        int n;
        cin>>n;
        for(int i=1;i<=50;i++)fa[i]=i;
        memset(mp,0,sizeof(mp));
        memset(du,0,sizeof(du));
        memset(s,0,sizeof(s));
        memset(vis,0,sizeof(vis));
        tot=0;
        for(int i=1;i<=n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            vis[u]=vis[v]=1;
            int fu=find(u),fv=find(v);
            fa[fu]=fv;
            mp[u][v]++;
            mp[v][u]++;
            du[u]++;
            du[v]++;
            tot++;
        }
        int cnt1=0;
        for(int i=1;i<=50;i++){
            if(vis[i]&&fa[i]==i)cnt1++;
        }
        if(cnt1>1){
            printf("Case #%d\nsome beads may be lost\n",kase);
            continue;
        }
        int flag=1;
        for(int i=1;i<=50;i++){
            if(du[i]&1){
                flag=0;
                break;
            }
        }
        if(!flag){
            printf("Case #%d\nsome beads may be lost\n",kase);
            if(kase<=T)printf("\n");
            continue;
        }
        temp=tot;
        for(int i=1;i<=50;i++){//找一個點
            if(vis[i]){
                dfs(i);
                break;
            }
        }
        printf("Case #%d\n",kase);
        for(int i=1;i<=tot;i++){
            printf("%d %d\n",s[i],s[i%tot+1]);
        }
        if(kase<=T)printf("\n");
    }
}
相關文章
相關標籤/搜索