弗罗莱算法是生成欧拉回路的算法之一,今天查看了许多资料,做一下记录整理。
1、关于欧拉图:
欧拉图是由哥尼斯堡桥问题抽象而来的。哥尼斯堡桥问题是指在Pregel河两岸就7座桥,问能否一次走完所有的桥并且不重复。问题如下:
将问题抽象后可以变为图问题。欧拉将此问题解决。所以称这种能遍历所有边且每条边至多且必须出现一次的图为欧拉图。称这种封闭路径为欧拉回路(此问题也称为一笔画问题)。
2、欧拉回路存在的充分必要条件:
给定一个无向连通图G=(V,E),其所有顶点的度为偶数 <=======> 此图是无向连通图。
证明过程不难,此处省略。
3、欧拉回路的生成算法:
生成欧拉回路的算法应该会有很多。在参考的离散数学资料中,有根据欧拉图证明过程生成欧拉回路的算法。此处给出算法的大体思想。
算法一:a:在图G中选择一个顶点作为起点,记为H。并将欧拉回路记做P,初始的欧拉回路只有H,并记做V(P) = {H}
b:在V(P)中选择任一顶点记为W,若W与V(G)-V(P)的点相关联,则扩展一条W-W的回路C,将路径记为P'---W----C-----W-----P''。
c:重复b直至P中包含所有边为止。
算法二:主要讲fleury算法。算法的思想为
任取v0∈V(G),令P0=v0;
设Pi=v0e1v1e2…ei vi已经行遍,按下面方法从中选取ei+1:
(a)ei+1与vi相关联;
(b)除非无别的边可供行遍,否则ei+1不应该为Gi=G-{e1,e2, …, ei}中的桥(所谓桥是一条删除后使连通图不再连通的边);
(c)当(b)不能再进行时,算法停止。
伪代码可能较为难懂,以通俗的语言描述就是随机选取v0作为欧拉回路的起点,v0入栈,按顺序选取与v0关联的点v1,v1入栈,删除v0----v1边,再选择与v1相关联的点,直到Vn,若无与Vn相关联的边则判断回路的边数是否 等于图的边数,若相等则算法结束,否则Vn出栈,选择V(n-1)的另一条边。
public void euler(int[][] graph,Stack s,int current,int start){
int num_edges; //graph中的边数
boolean flag = false; //是否还有与x关联的边
s.push(current);
for(int i = start; i < graph.length ; i++){
//从start开始搜索是否有边
if(graph[i][x] > 0){ //i与current有边
flag = true;
graph[i][current] = 0; graph[current][i] = 0; //删除边
euler(graph,s,i,0); //从i开始搜索
break;
}
}
if(flag){ //如果没有变与当前节点current相连
s.pop();
int m = s.peek();
G[m][current] = G[current][m] = 1; //恢复边
int new_start = current + 1;
if(s.size() == num_edges){ //完成回路
return;
}else{
euler(graph,s,m,new_start);
}
}
欧拉回路存储在栈s中。
4、例子:
(图片节选自外部,如有侵权,请联系)
按照算法的欧拉回路为
1---5--- 7--- 6--- 4--- 3--- 7--- 2--- 6--- 5--- 2--- 4--- 1