基本概念及定理
1. 歐拉通路、歐拉回路、歐拉圖
無向圖:
1) 設G是連通無向圖,則稱經過G的每條邊一次並且僅一次的路徑為歐拉通路;
2) 如果歐拉通路是回路(起點和終點是同一個頂點),則稱此回路為歐拉回路(Euler circuit);
3) 具有歐拉回路的無向圖G稱為歐拉圖(Euler graph)。
有向圖:
1) 設D是有向圖,D的基圖連通,則稱經過D的每條邊一次並且僅一次的有向路徑為有向
歐拉通路;
2) 如果有向歐拉通路是有向回路,則稱此有向回路為有向歐拉回路(directed Euler circuit);
3) 具有有向歐拉回路的有向圖D稱為有向歐拉圖(directed Euler graph)。
請思考圖5.1中的無向圖及有向圖是否為歐拉圖或有向歐拉圖。
圖5.1 歐拉回路及有向歐拉回路
2. 定理及推論
歐拉通路和歐拉回路的判定是很簡單的,請看下面的定理及推論。
定理5.1 無向圖G存在歐拉通路的充要條件是:
G為連通圖,並且G僅有兩個奇度結點(度數為奇數的頂點)或者無奇度結點。
推論5.1:
1) 當G是僅有兩個奇度結點的連通圖時,G的歐拉通路必以此兩個結點為端點。
2) 當G是無奇度結點的連通圖時,G必有歐拉回路。
3) G為歐拉圖(存在歐拉回路)的充分必要條件是G為無奇度結點的連通圖。
EXP圖5.1(a)所示的無向圖,存在兩個奇度頂點v2和v5,所以存在歐拉通路,且歐拉通路必
以這兩個頂點為起始頂點和終止頂點;該無向圖不存在歐拉回路。圖5.1(b)所示的無向圖為歐拉
圖。
定理5.2 有向圖D存在歐拉通路的充要條件是:
D為有向圖,D的基圖連通,並且所有頂點的出度與入度都相等;或者除兩個頂點外,其余
頂點的出度與入度都相等,而這兩個頂點中一個頂點的出度與入度之差為1,另一個頂點的出度
與入度之差為-1。
推論5.2:
1) 當D除出、入度之差為1,-1的兩個頂點之外,其余頂點的出度與入度都相等時,D的
有向歐拉通路必以出、入度之差為1的頂點作為始點,以出、入度之差為-1的頂點作為
終點。
2) 當D的所有頂點的出、入度都相等時,D中存在有向歐拉回路。
3) 有向圖D為有向歐拉圖的充分必要條件是D的基圖為連通圖,並且所有頂點的出、入度
都相等。
例如圖5.1(c)所示的有向圖,頂點v2和v4入度和出度均為1;頂點v1的出度為2、入度為1,
二者差值為1;頂 點v3的出度為1、入度為2,二者相差為-1;所以該有向圖只存在有向歐拉通路,
且必須以頂點v1為始點,以頂點v3為終點。圖5.1(d)所示的有向圖不存在有向歐拉通路。

1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 using namespace std; 5 const int MAX = 60; 6 int edge[MAX][MAX]; 7 int degree[MAX]; 8 int in[MAX],out[MAX]; 9 int n,type; //judge grape 類型 10 int e; //邊數 11 int top; // 棧底 初始化為 0; 12 int stack[MAX]; //記錄歐拉通路的路徑 13 int vis[MAX]; //是否已經訪問; 14 void DFS(int cur) //連通性的判斷 是否完全訪問掉 15 { 16 int i ; 17 for(i = 0; i<n; i++) 18 { 19 if(!vis[i]&&edge[cur][i]) 20 { 21 vis[i] = 1; 22 DFS(i); 23 } 24 } 25 } 26 27 28 // 判斷是否存在歐拉回路: 29 // 無向圖中: 連通圖且所有頂點度數為偶數 30 // 有向圖中: 連通圖且所有頂點的入度等於出度 31 bool judge() 32 { 33 memset(vis,0,sizeof(vis)); //訪問初始化 34 DFS(0); 35 for(int i =0; i<n; i++) 36 { 37 if(!vis[i]) 38 return false; 39 } //連通性的判斷 是否完全訪問掉 40 if(type) //有向圖 41 { 42 for (int i=0; i<n; i++) 43 if (in[i] != out[i]) 44 { 45 return false; 46 } 47 } 48 else //無向圖 49 { 50 for(int i =0; i<n; i++) 51 { 52 if(degree[i]%2) 53 { 54 return false; 55 } 56 } 57 } 58 return true; 59 } 60 // 有向圖的歐拉回路, 在 cur 點, 從 pos 點開始搜 61 void DFS_first(int cur ,int pos) 62 { 63 int i,a,b; 64 stack[top++] = cur; 65 for(i = pos;i<n;i++) 66 { 67 if(edge[cur][i] != 0) 68 { 69 edge[cur][i] = 0; 70 out[cur]--; 71 in[i]--; 72 DFS_first(i,0); 73 break; 74 } 75 } 76 if(i==n && top<n) // 走投無路, 而且還有邊的時候, 退回一步 77 { 78 b = stack[--top]; 79 a = stack[--top]; 80 edge[a][b] = 1; 81 out[a]++; 82 in[b]++; 83 DFS_first(a,b+1); 84 } 85 } 86 // 無向圖的歐拉回路, cur 點, 從 pos 點開始搜 87 void DFS_two(int cur,int pos) 88 { 89 int i,a,b; 90 stack[top++] = cur; 91 for(i = pos;i<n;i++) 92 { 93 if(edge[cur][i] != 0) 94 { 95 edge[i][cur] = 0; 96 edge[cur][i] = 0; 97 degree[cur]--; 98 degree[i]--; 99 DFS_two(i,0); 100 break; 101 } 102 } 103 if(i==n && top<n) // 走投無路, 而且還有邊的時候, 退回一步 104 { 105 b = stack[--top]; 106 a = stack[--top]; 107 edge[a][b] = 1; 108 edge[b][a] = 1; 109 degree[a]++; 110 degree[b]++; 111 DFS_two(a,b+1); 112 } 113 114 } 115 int main() 116 { 117 printf("0, 無向圖 1, 有向圖 : "); 118 scanf("%d", &type); 119 printf("輸入頂點個數: "); 120 scanf("%d",&n); 121 memset(edge,0,sizeof(edge)); 122 memset(degree,0,sizeof(degree)); //無向圖的度數 123 memset(in,0,sizeof(in)); //有向圖的入度 124 memset(out,0,sizeof(out)); //有向圖的出度 125 126 while(true) 127 { 128 int a,b; //邊集 129 scanf("%d %d",&a,&b); 130 if(!(a||b)) // 0 0 break 131 { 132 break; 133 } 134 edge[a][b] = 1; 135 in[b]++; 136 out[a]++; 137 if(!type) // 如果是無向圖 138 { 139 edge[b][a] = 1; 140 degree[a]++; //無向圖的度數 141 degree[b]++; 142 } 143 } 144 if(judge()) 145 { 146 printf("\n一條歐拉回路: "); 147 if(type) 148 DFS_first(0,0); 149 else 150 DFS_two(0,0); 151 for(int i =0; i<top; i++) 152 { 153 printf("%d",stack[i]); 154 if(i+1!=top) 155 printf(" -> "); 156 } 157 putchar('\n'); 158 } 159 else 160 { 161 printf("\n不存在歐拉回路!\n"); 162 } 163 return 0; 164 }
摘自《圖論算法理論、實現及應用-王桂平》