Euler Circuit & Euler Trail

Trail: a walk that does not repeat any edges.
Closed Trail(Circuit): a trail that begins and ends at the same vertex.
Eulerian Circuit: a circuit that includes every edge of the graph.
Eulerian Trail: a trail that includes every edge of the graph.

无向图中,图 $G$ 有欧拉回路当且仅当每个点的度数为偶数。
有向图中,图 $G$ 有欧拉回路当且仅当每个点的入度和出度相同。
无向图中,图 $G$ 有欧拉路径(非欧拉回路)当且仅当只有两个点的度数为奇数,其余都是偶数。
有向图中,图 $G$ 有欧拉路径(非欧拉回路)当且仅当只有两个点的入度和出度不同,且其中一个点的“入度 $-$ 出度=1”,另一个点的“出度 $-$ 入度=1”。

输出欧拉回路和欧拉路径的常用算法是 Hierholzer's Algorithm 和 Fleury's Algorithm,复杂度分别为 $O(E)$ 和 $O(E^2)$。

Hierholzer's Algorithm的正确性:因为一个具有欧拉回路的图G能够拆分成多个边不相交的环,因此这个算法正确。

 1 Find a circuit called $R_1$

 2 mark all edges of $R_1$

 3 i=1;

 4 while(true)

 5 {

 6     if $R_1$ contains all edges of G, then return;

 7     else

 8     {

 9         let $v_i$ be a vertex on $R_i$ that is incident with unmarked edge;

10         build a circuit $Q_i$ from $v_i$;

11         mark all edges of $Q_i$;

12         $R_{i+1} = R_i \cup Q_i$;

13         i++;

14     }

15 }
Hierholzer's Algorithm的伪代码
  1 import java.util.LinkedList;

  2 import java.util.List;

  3 import java.util.Scanner;

  4 

  5 public class EularTrail {

  6     int n;

  7     int m;

  8     int head[];

  9     int edge[][];

 10     int next[];

 11     int visited[];

 12     int ee = 0;    

 13     int indegree[];

 14     int outdegree[];

 15     LinkedList<Pair> queue = new LinkedList<Pair>();

 16     List<Integer> tmpList = new LinkedList<Integer>();

 17     List<Integer> resultList = new LinkedList<Integer>();

 18     

 19     int index[][];

 20     int start = 1;

 21     int end = 0;

 22     public boolean eularTrail(){

 23         calculateDegree();

 24         boolean isEularCircuit = hasEularCircuit();

 25         boolean isEularTrail = hasEularTrail();

 26         if(isEularTrail || isEularCircuit){

 27             tmpList.add(start);

 28             findCycle(start, 0);

 29             while(!queue.isEmpty()){

 30                 Pair u = queue.removeLast();    //注意这里只能用removeLast而不能用removeFirst

 31                 findCycle(u.vertex,u.pos);

 32             }

 33             printEular();

 34             return true;

 35         }

 36         else return false;

 37     }

 38     

 39     /**

 40      * 判定输入的路径是否是欧拉路径

 41      * @return

 42      */

 43     public boolean checkEularTrail(){

 44         System.out.println("###################");

 45         System.out.println("#Check Eular Trail#");

 46         System.out.println("###################");

 47         System.out.println("Input path:");

 48         Scanner in = new Scanner(System.in);

 49         boolean[] pathVisited = new boolean[m];

 50         for(int i=0;i<m;i++){

 51             pathVisited[i] = false;

 52         }

 53         int[] sequence = new int[m+1];

 54         for(int i=0;i<m+1;i++){

 55             sequence[i] = in.nextInt();

 56         }

 57         for(int i=0;i<m;i++){

 58             int begin = sequence[i];

 59             int end = sequence[i+1];

 60             pathVisited[index[begin][end]]=true;

 61         }

 62         for(int i=0;i<m;i++){

 63             if(pathVisited[i]==false){

 64                 System.out.println("\nNot a Eular Trail!");

 65                 return false;

 66             }

 67         }

 68         System.out.println("\nIs a Eular Trail!");

 69         return true;

 70     }

 71     

 72     private void calculateDegree() {

 73         for(int i=1;i<=n;i++){

 74             for(int j=head[i];j!=-1;j=next[j]){

 75                 outdegree[i]++;

 76                 indegree[edge[j][1]]++;

 77             }

 78         }

 79     }

 80     private void printEular(){

 81         for(int i=0;i<resultList.size();i++){

 82             System.out.println(resultList.get(i));

 83         }

 84     }

 85     private boolean hasEularTrail() {

 86         int start_count = 0;

 87         int end_count = 0;

 88         for(int i=1;i<=n;i++){

 89             if(indegree[i]!=outdegree[i]){

 90                 if((indegree[i]-outdegree[i])!=1 && (indegree[i]-outdegree[i])!=-1){

 91                     return false;

 92                 }

 93                 else if((indegree[i]-outdegree[i])==1){

 94                     end = i;

 95                     end_count++;

 96                 }

 97                 else if((indegree[i]-outdegree[i])==-1){

 98                     start = i;

 99                     start_count++;

100                 }

101             }

102         }

103         if(start_count!=1 || end_count!=1) return false;

104         return true;

105     }

106     

107     private void findCycle(int i,int begin) {

108         DFS(i,i,begin);

109         resultList.addAll(begin,tmpList);

110         tmpList.clear();

111     }

112     private boolean DFS(int source,int i,int begin){

113         if(outdegree[i]==0){

114             return true;

115         }

116         for(int j=head[i];j!=-1;j=next[j]){

117             int end = edge[j][1];

118             

119             if(visited[j]==0){

120                 visited[j] = 1;

121                 outdegree[i]--;

122                 if(outdegree[i]>0&&!queue.contains(i)){

123                     queue.add(new Pair(i,begin+tmpList.size()));

124                 }

125                 tmpList.add(end);

126                 if(end==source){

127                     if(outdegree[end]>0&&!queue.contains(end)){

128                         queue.add(new Pair(end,begin+tmpList.size()));

129                     }

130                     return false;

131                 }

132                 boolean flag =  DFS(source,edge[j][1],begin);

133                 if(flag==false){

134                     return false;

135                 }

136             }

137         }

138         return true;

139     }

140     

141     private boolean hasEularCircuit() {

142         for(int i=1;i<=n;i++){

143             if(indegree[i]!=outdegree[i]){

144                 return false;

145             }

146         }

147         return true;

148     }

149     public void input(){

150         System.out.println("Input Graph:");

151         Scanner in = new Scanner(System.in);

152         n = in.nextInt();

153         m = in.nextInt();

154         head = new int[n+1];

155         next = new int[m];

156         edge = new int[m][2];

157         visited = new int[m];

158         indegree = new int[n+1];

159         outdegree = new int[n+1];

160         index = new int[n+1][n+1];

161         for(int i=1;i<=n;i++){

162             head[i] = -1;

163             outdegree[i] = 0;

164             indegree[i] = 0;

165         }

166         for(int i=0;i<m;i++){

167             next[i] = -1;

168             visited[i] = 0;

169         }

170         for(int i=1;i<=m;i++){

171             int begin = in.nextInt();

172             int end = in.nextInt();

173             edge[ee][0] = begin;

174             edge[ee][1] = end;

175             next[ee] = head[begin];

176             head[begin] = ee;

177             index[begin][end] = ee;

178             ee++;

179         }

180     }

181     public static void main(String[] args) {

182         EularTrail hierholzer = new EularTrail();

183         hierholzer.input();

184         hierholzer.eularTrail();

185         //boolean flag = hierholzer.checkEularTrail();

186         //System.out.println(flag);

187     }

188 }
Eular Trail的Java实现
  1 import java.util.LinkedList;

  2 import java.util.List;

  3 import java.util.Scanner;

  4 

  5 class Pair{

  6     int vertex;

  7     int pos;

  8     public Pair(int vertex,int pos){

  9         this.vertex = vertex;

 10         this.pos = pos;

 11     }

 12     @Override

 13     public String toString() {

 14         return "Pair [vertex=" + vertex + ", pos=" + pos + "]";

 15     }

 16 }

 17 public class EularCircuit {

 18     int n;

 19     int m;

 20     int head[];

 21     int edge[][];

 22     int next[];

 23     int visited[];

 24     int ee = 0;    

 25     int indegree[];

 26     int outdegree[];

 27     LinkedList<Pair> queue = new LinkedList<Pair>();

 28     List<Integer> tmpList = new LinkedList<Integer>();

 29     List<Integer> resultList = new LinkedList<Integer>();

 30     

 31     int index[][];

 32     public boolean eularCircuit(){

 33         calculateDegree();

 34         boolean isEular = hasEularCircuit();

 35         if(!isEular) return false;

 36         tmpList.add(1);

 37         findCycle(1, 0);

 38         while(!queue.isEmpty()){

 39             Pair u = queue.removeLast();    //注意这里只能用removeLast而不能用removeFirst

 40             findCycle(u.vertex,u.pos);

 41         }

 42         printEular();

 43         return true;

 44     }

 45     /**

 46      * 判定输入的路径是否是欧拉回路

 47      * @return

 48      */

 49     public boolean checkEularCircuit(){

 50         System.out.println("#####################");

 51         System.out.println("#Check Eular Circuit#");

 52         System.out.println("#####################");

 53         System.out.println("Input path:");

 54         Scanner in = new Scanner(System.in);

 55         boolean[] pathVisited = new boolean[m];

 56         for(int i=0;i<m;i++){

 57             pathVisited[i] = false;

 58         }

 59         int[] sequence = new int[m+1];

 60         for(int i=0;i<m+1;i++){

 61             sequence[i] = in.nextInt();

 62         }

 63         if(sequence[0]!=sequence[m]) {

 64             System.out.println("\nNot a Eular Circuit!");

 65             return false;

 66         }

 67         for(int i=0;i<m;i++){

 68             int begin = sequence[i];

 69             int end = sequence[i+1];

 70             pathVisited[index[begin][end]]=true;

 71         }

 72         for(int i=0;i<m;i++){

 73             if(pathVisited[i]==false){

 74                 System.out.println("\nNot a Eular Circuit!");

 75                 return false;

 76             }

 77         }

 78         System.out.println("\nIs a Eular Circuit!");

 79         return true;

 80     }

 81     public void input(){

 82         System.out.println("Input Graph:");

 83         Scanner in = new Scanner(System.in);

 84         n = in.nextInt();

 85         m = in.nextInt();

 86         head = new int[n+1];

 87         next = new int[m];

 88         edge = new int[m][2];

 89         visited = new int[m];

 90         indegree = new int[n+1];

 91         outdegree = new int[n+1];

 92         index = new int[n+1][n+1];

 93         for(int i=1;i<=n;i++){

 94             head[i] = -1;

 95             outdegree[i] = 0;

 96             indegree[i] = 0;

 97         }

 98         for(int i=0;i<m;i++){

 99             next[i] = -1;

100             visited[i] = 0;

101         }

102         for(int i=1;i<=m;i++){

103             int begin = in.nextInt();

104             int end = in.nextInt();

105             edge[ee][0] = begin;

106             edge[ee][1] = end;

107             next[ee] = head[begin];

108             head[begin] = ee;

109             index[begin][end] = ee;

110             ee++;

111         }

112     }

113 

114     private void calculateDegree() {

115         for(int i=1;i<=n;i++){

116             for(int j=head[i];j!=-1;j=next[j]){

117                 outdegree[i]++;

118                 indegree[edge[j][1]]++;

119             }

120         }

121     }

122     private boolean hasEularCircuit() {

123         for(int i=1;i<=n;i++){

124             if(indegree[i]!=outdegree[i]){

125                 return false;

126             }

127         }

128         return true;

129     }

130     /*从i开始寻找一个环,即 i->....->i */

131     private void findCycle(int i,int begin) {

132         DFS(i,i,begin);

133         resultList.addAll(begin,tmpList);

134         tmpList.clear();

135     }

136     

137     private boolean DFS(int source,int i,int begin){

138         if(outdegree[i]==0){

139             return true;

140         }

141         for(int j=head[i];j!=-1;j=next[j]){

142             int end = edge[j][1];

143             

144             if(visited[j]==0){

145                 visited[j] = 1;

146                 outdegree[i]--;

147                 if(outdegree[i]>0&&!queue.contains(i)){

148                     queue.add(new Pair(i,begin+tmpList.size()));

149                 }

150                 tmpList.add(end);

151                 if(end==source){

152                     if(outdegree[end]>0&&!queue.contains(end)){

153                         queue.add(new Pair(end,begin+tmpList.size()));

154                     }

155                     return false;

156                 }

157                 boolean flag =  DFS(source,edge[j][1],begin);

158                 if(flag==false){

159                     return false;

160                 }

161             }

162         }

163         return true;

164     }

165     /*输出欧拉回路*/

166     private void printEular(){

167         for(int i=0;i<resultList.size();i++){

168             System.out.println(resultList.get(i));

169         }

170     }

171     

172     public static void main(String[] args) {

173         EularCircuit hierholzer = new EularCircuit();

174         hierholzer.input();

175         hierholzer.eularCircuit();

176         boolean flag = hierholzer.checkEularCircuit();

177         System.out.println(flag);

178     }

179     

180 }
Eular Circuit的Java实现

其中,EularCircuit 类的功能:

  • 输入图
  • 检测给定序列是否为欧拉回路
  • 输出欧拉回路

EularTrail 类的功能:

  • 输入图
  • 检测给定序列是否为欧拉路径
  • 输出欧拉路径

 

16 56

1 2

2 1

1 5

5 1

2 3

3 2

2 5

5 2

2 6

6 2

3 4

4 3

3 7

7 3

3 8

8 3

4 8

8 4

5 6

6 5

5 9

9 5

6 7

7 6

6 10

10 6

7 8

8 7

7 11

11 7

8 12

12 8

9 10

10 9

9 13

13 9

9 14

14 9

10 11

11 10

10 14

14 10

11 12

12 11

11 15

15 11

12 15

15 12

12 16

16 12

13 14

14 13

14 15

15 14

15 16

16 15
Sample Input of Eular Circuit
1

5

9

14

15

16

15

14

13

14

10

14

9

13

9

10

11

15

12

16

12

15

11

12

11

10

9

5

6

10

6

7

11

7

8

12

8

7

6

5

2

6

2

5

1

2

3

8

4

8

3

7

3

4

3

2

1
Sample Output of Eular Circuit
4 5

1 4

4 3

3 2

2 1

1 3
Sample Input of Eular Trail
1

3

2

1

4

3
Sample Output of Eular Trail

 

 

 

 

你可能感兴趣的:(Euler)