一、问题描述
根据图上描述,事实上一步走完是不可能的。可以用如下性质来判断欧拉回路与欧拉道路。
1、如果一个无向图是连通的,且最多只有两个并且最少要包含一个奇点(度数为奇数),则一定存在欧拉道路。
2、如果有两个奇点,它们必须是起点和终点。
3、如果奇点不存在,可以从任意点出发,最终一定会回到该点,称为欧拉回路。
4、对于有向图,欧拉道路存在的充要条件是:最多只能有两个点的入度不等于出度,而且必须是其中的一个点的出度恰好比入度大一(起点),另一个的入度比出度大1(终点)。
二、代码实现
打印出欧拉道路:
1 import java.util.Stack; 2 3 public class 图的dfs_euler { 4 static Stack<String> path = new Stack<>(); 5 // 图的邻接矩阵 6 private static int[][] graph = { 7 { 0, 1, 2, 1 }, // 这里的2 不代表权值,代表路的个数,表示A->C有两条路 8 { 1, 0, 0, 0 }, 9 { 2, 0, 0, 1 }, 10 { 1, 0, 1, 0 } 11 }; 12 // 节点数 13 private static final int n = 4; 14 // 标记边的访问情况,因为通路是双向的,所以用二维数组 15 private static int[][] vis = new int[n][n]; 16 17 /** 18 * 19 * @param u 现在访问的顶点 20 */ 21 static void euler(int u) { 22 // 其他顶点 23 for (int v = 0; v < n; v++) { 24 // 有边,且访问次数少于连接数 25 if (graph[u][v] > 0 && vis[u][v] < graph[u][v]) { 26 // 路是双向的 27 vis[u][v]++; 28 vis[v][u]++; 29 // v作为新的起点,递归 30 euler(v); 31 // 已走u->v,将这一步走法加入栈中 32 path.push((char) ('A' + u) + "->" + (char) ('A' + v)); 33 } 34 } 35 } 36 37 public static void main(String[] args) { 38 euler(2); // 参数不同,结果不唯一 39 while (!path.isEmpty()) 40 System.out.println(path.pop()); 41 } 42 }
代码中表示的图为:
三、结果:
四、图的DFS小结
在图论中使用到深搜来遍历图的节点,在拓扑排序中也使用到了深搜来进行排序,其中在dfs退回来之后需要对退回来的状态进行处理,把相关位置进行标记,其中使用可以使用到标记来判断有向图是否有环。在图论中可以结合四连通、八连通简单问题理解深搜,拓扑排序来理解深搜。
在图论中DFS最重要的就是要进行标记。但是有时在回溯的时候我们需要把这些访问过的痕迹都清除掉,因为在下一次尝试的过程中有可能访问到这个地方所以需要进行清除。