歐拉路徑詳解


什么是歐拉路徑?歐拉路徑就是一條能夠不重不漏地經過圖上的每一條邊的路徑,即小學奧數中的一筆畫問題。而若這條路徑的起點和終點相同,則將這條路徑稱為歐拉回路。

如何判斷一個圖是否有歐拉路徑呢?顯然,與一筆畫問題相同,一個圖有歐拉路徑需要以下幾個條件:

  • 首先,這是一個連通圖
  • 若是無向圖,則這個圖的度數為奇數的點的個數必須是0或2;若是有向圖,則要么所有點的入度和出度相等,要么有且只有兩個點的入度分別比出度大1和少1

上面這兩個條件很好證明。查找歐拉路徑前,必須先保證該圖滿足以上兩個條件,否則直接判誤即可。

查找歐拉路徑的算法有Fluery算法和Hierholzer算法。下面介紹一下Hierholzer算法。

算法流程:

  1. 對於無向圖,判斷度數為奇數的點的個數,若為0,則設任意一點為起點,若為2,則從這2個點中任取一個作為起點;對於有向圖,判斷入度和出度不同的點的個數,若為0,則設任意一點為起點,若為2,則設入度比出度小1的點為起點,另一點為終點。具體起點的選擇要視題目要求而定。
  2. 從起點開始進行遞歸:對於當前節點x,掃描與x相連的所有邊,當掃描到一條(x,y)時,刪除該邊,並遞歸y。掃描完所有邊后,將x加入答案隊列。
  3. 倒序輸出答案隊列。(因為這里是倒序輸出,我們可以用棧來存儲答案,當然用雙端隊列也可以)

解析:

從起點開始,每一次執行遞歸函數,相當於模擬一筆畫的過程。遞歸的邊界顯然就是路徑的終點,對於一個有歐拉路徑的圖,此時圖上的所有邊都已被刪除,自然就不能繼續遞歸。由於存儲答案是在遍歷以后進行的,答案存儲也就是倒序的,因此要倒序輸出答案。

代碼:

#include<iostream>
#include<stack>
using namespace std;
const int N=500;
int n,tot,c=N,jp[N],cnt[N],edge[N][N];
char a,b;
stack<int> q;
void dfs(int now)
{
    for(int i=1;i<=N;i++)
        if(edge[now][i]==1)
        {
            edge[now][i]--,edge[i][now]--;
            dfs(i);
        }
    q.push(now);//加入答案隊列
}//算法過程
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a>>b;
        c=min(c,a);
        c=min(c,b);
        edge[a][b]++,edge[b][a]++;
        cnt[a]++;
        cnt[b]++;//統計每個節點的度數
    }
    for(int i=1;i<=N;i++)
        if(cnt[i]%2==1)
            jp[tot++]=i;//找出度數為奇數的節點
    if(tot!=2 && tot)
    {
        cout<<"No Solution";
        return 0;
    }//若該圖沒有歐拉路徑則判誤
    int stat;
    if(tot)
        stat=min(jp[0],jp[1]);
    else
        stat=c;//找出起點
    dfs(stat);
    while(!q.empty())
    {
        char ct=q.top();
        cout<<ct;
        q.pop();
    }//倒序輸出
    return 0;
}

在上面的代碼中,找出的是起點字典序最小的歐拉路徑,具體情況應視題意而定。


習題:


2019.4.16 於廈門外國語學校石獅分校


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM