如何寻找欧拉回路、欧拉通路(套圈法)

 

如何寻找欧拉回路、欧拉通路(套圈法)

传说中的套圈法。

 

算法思想的朴素表达

 

对于欧拉图,从一个节点出发,随便往下走(走过之后需要标记一下,下次就不要来了),必然也在这个节点终止(因为除了起始节点,其他节点的度数都是偶数,只要能进去就能出来)。这样就构成了一个圈,但因为是随便走的,所以可能会有些边还没走过就回来了。我们就从终止节点逆着往前查找,直到找到第一个分叉路口,然后从这个节点出发继续上面的步骤,肯定也是可以找到一条回到这个点的路径的,这时我们把两个圈连在一起。当你把所有的圈都找出来后,整个欧拉回路的寻找就完成了。

 

寻找欧拉回路时,起始节点是可以任意选择的。如果是有基度顶点要寻找欧拉通路,则从基度顶点出发就好了,上述步骤依然有效。

 

算法思想的书面表达 

 

一个解决此类问题基本的想法是从某个节点开始,然后查出一个从这个点出发回到这个点的环路径。现在,环已经建立,这种方法保证每个点都被遍历.如果有某个点的边没有被遍历就让这个点为起点,这条边为起始边,把它和当前的环衔接上。这样直至所有的边都被遍历。这样,整个图就被连接到一起了。 

 

更正式的说,要找出欧拉路径,就要循环地找出出发点。按以下步骤: 

 

任取一个起点,开始下面的步骤 

如果该点没有相连的点,就将该点加进路径中然后返回。 

如果该点有相连的点,就列一张相连点的表然后遍历它们直到该点没有相连的点。(遍历一个点,删除一个点) 

处理当前的点,删除和这个点相连的边, 在它相邻的点上重复上面的步骤,把当前这个点加入路径中. 

下面是伪代码: 

 

# circuit is a global array 

find_euler_circuit 

circuitpos = 0 

find_circuit(node 1) 

 

# nextnode and visited is a local array 

# the path will be found in reverse order 

find_circuit(node i) 

 

if node i has no neighbors then 

circuit(circuitpos) = node i 

circuitpos = circuitpos + 1 

else 

while (node i has neighbors) 

pick a random neighbor node j of node i 

delete_edges (node j, node i) 

find_circuit (node j) 

circuit(circuitpos) = node i 

circuitpos = circuitpos + 1 

要找欧拉路径, 只要简单的找出一个度为奇数的节点,然后调用 find_circuit 就可以了. 

 

一点点代码(pku 2337里面截过来的,具体请看http://blog.csdn.net/logic_nut/archive/2009/08/22/4473174.aspx) 

 

view plaincopy to clipboardprint?

//主函数中调用下面这个函数   

euler(start, -1); //因为直接从start出发,所以第二个参数用-1代替,输出的时候要忽略掉。   

//euler函数就是用的传说中的套圈法,是一个迭代的过程   

//npath是一个全局变量,记录已经找到的边的数量   

//边存储在adj[]中,是用数组实现的链表结构(就跟很多hash那样,首节点的数据域不用,只有指针部分有效)   

void euler(int cur, int edgeN) //cur当前到达的节点 edgeN上一被选择的边,即上一个节点通过edgeN到达的cur   

{    

    int i;   

    while(adj[cur].nxt != -1)   

    {   

        i=adj[cur].nxt;   

        adj[cur].nxt=adj[i].nxt;//相当于是删除掉使用了的边   

        euler(adj[i].end,i);   

    }   

    path[npath++] = edgeN; //后序记录,如果要保持搜索时候边的优先级,则逆向输出   

}  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值