欧拉回路(Euler Circuit)是数学家欧拉(Euler)在研究著名的德国哥尼斯堡(Koenigsberg)七桥问题时发现的。
如下图所示,流经哥尼斯堡的普雷格尔河中有两个岛,两个岛与两岸共4处陆地通过7座桥彼此相联。7桥问题就是如何能从任一处陆地出发,经过且经过每个桥一次后回到原出发点。
欧拉由此提出了著名的欧拉定理。
1)欧拉路(Euler Path):通过图中所有边的简单路。
2)欧拉回路(Euler Circuit):闭合的欧拉路。
3)欧拉图(Euler Graph):包含欧拉回路的图。
欧拉路:图G,若存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路。
欧拉回路:图G,如果存在一条回路经过G每条边有且仅有一次,称这条回路为欧拉回路。
欧拉图:具有欧拉回路的图成为欧拉图。
判断欧拉路是否存在的方法
有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是 出度=入度。
无向图:图连通,只有2个顶点是奇数度,其余都是偶数度的。
判断欧拉回路是否存在的方法
有向图:图连通,所有的顶点出度=入度。
无向图:图连通,所有顶点都是偶数度。
推论:
1、凡是由偶点组成的连通图,一定可以一笔画成。
2、凡是只有两个奇点的连通图(其余都为偶点),一定可以一笔画成。
3、其他情况的图都不能一笔画出。
如图1所示:图1是一个无向图,图中有5个顶点(Vertex),5条边(Edge)。
这个图中存在欧拉路(Euler Path),例如:4-3-0-1-2-0;但是不存在欧拉回路(Euler Circuit)。
注意:顶点0具有奇数度(3);顶点4具有奇数度(1)
如图2所示:图2的无向图存在欧拉回路(Euler Circuit),例如:2-1-0-3-4-0-2。
所有顶点的度都是偶数度。
如图3所示:图3的无向图不是一张欧拉图(Euler Graph),因为不包含欧拉回路(Euler Circuit)。
图3中有4个顶点都是奇数度。
package com.bean.algorithm.basic;
import java.util.Iterator;
import java.util.LinkedList;
public class EulerCircuit2 {
private int V; // 顶点( vertices)的数量
// 邻接表( Adjacency List Representation)表示
private LinkedList adj[];
// 构造方法
EulerCircuit2(int v)
{
V = v;
adj = new LinkedList[v];
for (int i=0; i i = adj[v].listIterator();
while (i.hasNext())
{
int n = i.next();
if (!visited[n])
DFSUtil(n, visited);
}
}
// 检查所有非零度顶点是否连接
boolean isConnected()
{
// 标记所有顶点为未访问状态
boolean visited[] = new boolean[V];
int i;
for (i = 0; i < V; i++)
visited[i] = false;
// 找到非0度的顶点
for (i = 0; i < V; i++)
if (adj[i].size() != 0)
break;
if (i == V)
return true;
DFSUtil(i, visited);
for (i = 0; i < V; i++)
if (visited[i] == false && adj[i].size() > 0)
return false;
return true;
}
/* 返回值说明
0 --> 图不是欧拉图 Eulerian则返回0
1 --> 如果图中存在欧拉路则返回1 (Semi-Eulerian)
2 --> 如果图中存在欧拉回路则返回2 Euler Circuit (Eulerian) */
int isEulerian()
{
// 检查是否连接了所有非零度顶点
if (isConnected() == false)
return 0;
// 统计奇数度的顶点
int odd = 0;
for (int i = 0; i < V; i++)
if (adj[i].size()%2!=0)
odd++;
// If count is more than 2, then graph is not Eulerian
if (odd > 2)
return 0;
// If odd count is 2, then semi-eulerian.
// If odd count is 0, then eulerian
// Note that odd count can never be 1 for undirected graph
return (odd==2)? 1 : 2;
}
// Function to run test cases
public void test()
{
int res = isEulerian();
if (res == 0)
System.out.println("图 不是 欧拉图 Eulerian");
else if (res == 1)
System.out.println("图 包含 欧拉路 Euler path");
else
System.out.println("图 包含 欧拉回路 Euler cycle");
}
public static void main(String args[]) {
EulerCircuit2 g1 = new EulerCircuit2(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
g1.test();
EulerCircuit2 g2 = new EulerCircuit2(5);
g2.addEdge(1, 0);
g2.addEdge(0, 2);
g2.addEdge(2, 1);
g2.addEdge(0, 3);
g2.addEdge(3, 4);
g2.addEdge(4, 0);
g2.test();
EulerCircuit2 g3 = new EulerCircuit2(5);
g3.addEdge(1, 0);
g3.addEdge(0, 2);
g3.addEdge(2, 1);
g3.addEdge(0, 3);
g3.addEdge(3, 4);
g3.addEdge(1, 3);
g3.test();
EulerCircuit2 g4 = new EulerCircuit2(6); // 6个顶点,10条边
g4.addEdge(0, 1);
g4.addEdge(1, 2);
g4.addEdge(2, 0);
g4.addEdge(3, 4);
g4.addEdge(4, 5);
g4.addEdge(5, 3);
g4.addEdge(0, 3);
g4.addEdge(0, 5);
g4.addEdge(2, 3);
g4.addEdge(2, 5);
g4.test();
EulerCircuit2 g5 = new EulerCircuit2(5);
g5.addEdge(0, 1);
g5.addEdge(0, 2);
g5.addEdge(1, 2);
g5.addEdge(1, 3);
g5.addEdge(1, 4);
g5.addEdge(4, 2);
g5.addEdge(4, 3);
g5.addEdge(2, 3);
g5.test();
EulerCircuit2 g6 = new EulerCircuit2(3);
g6.addEdge(0, 1);
g6.addEdge(1, 2);
g6.addEdge(2, 0);
g6.test();
EulerCircuit2 g7 = new EulerCircuit2(3);
g7.test();
}
}
程序运行结果:
图 包含 欧拉路 Euler path
图 包含 欧拉回路 Euler cycle
图 不是 欧拉图 Eulerian
图 包含 欧拉回路 Euler cycle
图 包含 欧拉路 Euler path
图 包含 欧拉回路 Euler cycle
图 包含 欧拉回路 Euler cycle