歐拉圖


一. 基本概念

  • 歐拉圖是指通過圖(無向圖或有向圖)中所有邊且每邊僅通過一次通路,相應的回路稱為歐拉回路。具有歐拉回路的圖稱為歐拉圖(\(Euler Graph\)),具有歐拉通路而無歐拉回路的圖稱為半歐拉圖。(\(from\)百度百科)

  • 有沒有發現很像小時候玩的一筆畫問題?

歐拉路分為歐拉通路和歐拉回路

歐拉通路:從一個點出發,不重復地經過每條邊,從另一個點結束。

歐拉回路:從一個點出發,不重復地經過每條邊,又回到該點結束。

判斷方法(性質):

  • 無向圖

通路:有且僅有兩個點的度數為奇數,其他點的度數均為偶數。

回路:所有點的度數均為偶數。

  • 有向圖

通路:有一個點的出度比入度大 \(1\),另一個點的出度比入度小 \(1\),其他點的出度與入度相等。

回路:所有點的出度與入度相等。


二. 判斷方法

判斷一個圖是否有歐拉通路或歐拉回路,一般用到弗勒里(\(Fleury\))算法。該算法用 \(DFS\) 實現。(大法師又雙叒叕登場了)

\({\color{Red}{Fleury 算法的核心是:除非都是橋,否則走非橋邊。}}\)

\({\color{Green}{但實際上並不需要判斷是不是橋,當走完某條邊后不能再走時,我們將其放入棧內(不是隊列!!!),當全部邊都走過后再把棧內的邊輸出。}}\)

舉個栗子

\(DFS\) 開始,從 \(1\) 號點出發,我們的遍歷順序:

\(1 \to 2 \quad 2 \to 3 \quad 3 \to 1\)

這時發現走不動了,於是我們回溯到 \(3\) 號點,棧內情況:

\(3 \to 1\)

\(3\) 號點也走不了了,回溯到 \(2\) 號點,棧內情況:

\(2 \to 3\)
\(3 \to 1\)

\(2\) 號點繼續走:

\(2 \to 4 \quad 4 \to 5 \quad 5 \to 2\)

\(2\) 號點走不了了,回溯,棧內情況:

\(5 \to 2\)
\(2 \to 3\)
\(3 \to 1\)

\(5\) 號點回溯:

\(4 \to 5\)
\(5 \to 2\)
\(2 \to 3\)
\(3 \to 1\)

\(4\) 號點回溯:

\(2 \to 4\)
\(4 \to 5\)
\(5 \to 2\)
\(2 \to 3\)
\(3 \to 1\)

\(2\) 號點回溯:

\(1 \to 2\)
\(2 \to 4\)
\(4 \to 5\)
\(5 \to 2\)
\(2 \to 3\)
\(3 \to 1\)

\(1\) 號點也走不了,\(DFS\) 結束。

最終輸出路徑:

\(1 \to 2 \quad 2 \to 4 \quad 4 \to 5 \quad 5 \to 2 \quad 2 \to 3 \quad 3 \to 1\)

這是一條符合條件的路徑。

三. 小試牛刀

Problem A: 世界人民大團結 \(\color{Red}{Special\,Judge}\)

Description

現在,世界的主題是和平與發展。社會學博士老 \(Z\) 認為,要實現和平發展,首先要實現世界人民大團結。

世界上有 \(n\) 個人。他們胸前和背后各有一個自然數,大於或等於 \(0\) 且小於或等於 \(6\)。兩個身上帶有某個相同數字的人把身上相同的數字合在一起,就實現了團結。比如,\((0,1)(1,2)\) 就實現了團結,而 \((0,1)(2,1)\)\((0,0)(1,2)\) 都不是團結。把數合在一起的方法,是胸靠胸、背靠背、背靠胸或胸靠背。請判斷世界人民能否實現大團結。如果能,請輸出大團結的實現方案。

Input

第一行,一個正整數 \(n\),表示世界上有 \(n\) 個人。
剩余 \(n\) 行,每行是用空格隔開的兩個自然數,大於等於 \(0\) 且小於等於 \(6\),第 \((i+1)\) 行表示第 \(i\) 個人胸前和背后的數字。

Output

如大團結可以實現,輸出 \(n\) ,每行兩個空格隔開的數字。第一個是人的編號(同輸入);第二個是“\(-\)”或“\(+\)”,“\(+\)”表示這個人胸在前,背在后,“\(-\)”反之。人們按照你輸出的順序和面對的方向從前到后站立。具體參見樣例。
如大團結不能實現,輸出一行“\(No\,Solution\)”(不含引號)。

Sample Input

5
1 2
2 4
2 4
6 4
2 1

Sample Output

2 -
5 +
1 +
3 +
4 -

HINT

對於 \(100\%\) 的數據,\(1 \le n \le 100\)

思路

模板題,將數字看成點,人看成邊,起點隨便選(如最小的點)。

\(\color{Blue}{(樣例沒過,害得我調了半天,結果發現是Special Judge……)}\)

參考代碼

#include <iostream>
#include <stack>
using namespace std;
 
const int INF = 0x3f3f3f3f;
const int MAXN = 1e2 + 5;
 
int n, cnt, s = INF;
int du[MAXN], e[MAXN][MAXN], a[MAXN], b[MAXN];
stack <int> st;
 
void dfs(int now)
{
    for (int i = 0; i <= 6; ++i)
    {
        if (e[now][i])
        {
            --e[now][i];
            --e[i][now];
            --du[now];
            --du[i];
            dfs(i);
        }
    }
    st.push(now);
}
 
void euler()
{
    int last = st.top();
    st.pop();
    while (!st.empty())
    {
        int now = st.top();
        st.pop();
        for (int i = 1; i <= n; ++i)
        {
            if (a[i] == last && b[i] == now)
            {
                cout << i << " +\n";
                a[i] = -INF;
                b[i] = -INF;
                break;
            }
            else if (a[i] == now && b[i] == last)
            {
                cout << i << " -\n";
                a[i] = -INF;
                b[i] = -INF;
                break;
            }
        }
        last = now;
    }
}
 
int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i] >> b[i];
        ++du[a[i]];
        ++du[b[i]];
        s = min(s, min(a[i], b[i]));
        ++e[a[i]][b[i]];
        ++e[b[i]][a[i]];
    }
    for (int i = 0; i <= 6; ++i)
    {
        if (du[i] % 2)
        {
            ++cnt;
            if (cnt == 1)
            {
                s = i;
            }
        }
    }
    if (cnt != 0 && cnt != 2)
    {
        puts("No Solution");
        return 0;
    }
    dfs(s);
    for (int i = 0; i <= 6; ++i)
    {
        if (du[i])
        {
            puts("No Solution");
            return 0;
        }
    }
    euler();
    return 0;
}
/**************************************************************
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:2224 kb
****************************************************************/


免責聲明!

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



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