欧拉图与中国邮递员问题算法

一、什么是中国邮递员问题?

在一个已知的地区,邮差要设法找到一条最短路径,可以走过此地区所有的街道,且最后要回到出发点。

中国邮递员问题由管梅谷教授在1962年提出。

我们会想到利用图来解决中国邮递员问题,其中就有种专门针对这种只访问一次路径的图的概念,称作欧拉图,由瑞士数学家Leonhard
Euler(鼎鼎有名的欧拉)提出。下面开始欧拉图的一些基本概念。

二、欧拉路径和欧拉回路

1、图的一些基本概念:

    • 图:记作G=(V,E),是一个由顶点V和边E构成的有限集合。

    • 多重图(multi-graph):是一个允许有多重边的图,也就是有至少二个边的二个顶点完全相同,至少有二个顶点可以由二个边相连接。

    • 割边(cut-edge):假设有连通图G,e是其中一条边,如果G-e(排除边e之后)是不连通的,则边e是图G的一条割边。

    • 生成子图(spanning
      subgraph):一个图H是图G的子图,当图H的顶点是图G的顶点的子集,图H的边是图G的边的子集。图H是图G的生成子图,当图H的顶点与图H的顶点是相同的。(我们能通过图H张成图G,H spans G)

2、有向图的一些基本概念:

    • 出度(out-degree):记作d+(v),指的是关联于(incident
      from)顶点v的边的数量。

    • 入度(in-degree):记作d-(v),指的是关联至(incident
      to)顶点v的边的数量。

    • 平衡(balanced):一个有向图是平衡的,即当对于每个顶点v,d+(v)=d-(v)。

    • 强连通(strongly
      connected):强连通是指有向图G中任意两点v1、v2之间都存在着v1到v2的路径及v2到v1的路径。一个有向图是强连通的,当且仅当G中有一个回路,它至少包含每个顶点一次。

3、欧拉图的一些基本概念:

    • 欧拉路径:若图G存在这样一条路径,使得恰好经过G中每条边有且仅有一次,则称该路径为欧拉路径。

    • 欧拉回路:如果存在一条回路经过G每条边有且仅有一次,则称这条回路为欧拉回路。

    • 欧拉图:包含有欧拉回路的图。

      图中的欧拉回路与欧拉路径的例子:

4、判断图是否存在欧拉回路(或欧拉路径)的方法:

定理1(无向图存在欧拉回路的条件):一个无向的多重图G存在欧拉回路,当且仅当图是连通图且奇点的个数为0。

证明:(证明这个定理是和著名的七桥问题是一致的)。

NULL

定理2(无向图存在欧拉路径的条件):一个无向的多重图G存在欧拉路径,当且仅当图是连通图且奇点的个数为2。

推论1(有向图存在欧拉回路的条件):一个有向图G是欧拉图,当且仅当图是连通图且平衡;

推论2(有向图存在欧拉路径的条件):一个有向图G存在欧拉路径当且仅当图是连通图且其顶点的度满足以下条件:

(1)d+(v)=d-(v)
对于所有v≠v1或v2

(2)d+(v1)=d-(v1)+1;

(3)d-(v1)=d+(v2)+1。

三、寻找欧拉回路

如何在给定的一个图中寻找欧拉回路。

1、在无向图G=(V,E)中找欧拉回路的算法

弗罗莱(Fleury)算法可以在无向图中寻找欧拉回路,主要思路是尽量避开割边来走。

选取出发点v0∈V,令P0=v0

设Pi=v0e1v1e2
… eivi已经遍历,按下面方法从中选取ei+1

(1)ei+1与vi相关联;

(2)除非无别的边可供行遍,否则ei+1不应该为Gi=G-{e1,e2,
…, ei}中的割边;

(3)当(2)不能再进行时,算法停止。

通过借助图的例子进行算法的演算过程:

算法:

CV:当前顶点;

E`:已遍历的边的集合;

EC已访问的顶点的集合;

w:第一个顶点;

A(v):在图(G-E`)中的邻接于顶点v的邻接列表。

    1. EC←[w]

    2. CVw

    3. E`

    4. while
      |A(w)|>0 do


    5. begin


    6. if
      |A(CV)| > 1 then

    7. Find a
      vertex vA(CV)
      such that (CV , v) is not a cut-edge of
      (G-E`)


    8. else
      let the vertex in A(CV) be denoted by
      v

    9. delete v in A(CV) and CV in
      A(v)


    10. E`
      E` ∪ {(CV , v)}


    11. CV
      v

    12. add CV to the tail of EC


    13. end

    14. Output
      EC

算法的复杂度:

O(|E|2)

算法有效性证明:

NULL

2、有向图G=(V,E)中寻找欧拉回路

Spanning
out-tree:

首先,先根据有向欧拉图G构造一棵以顶点u为根spanning out-tree T。方法如下:

保留第一条关联至除顶点u外的每一个顶点的边,构成spanning
out-tree T。T是有向欧拉图G的子图,利用这个结构可以找到图G的欧拉回路。

如图。

定理:如果图G是连通且平衡的有向图,并且知道了以u为根的spanning out-tree T,则可以通过以下方法获得欧拉回路:

(a)初始边可以是关联至u的任意一条边。

(b)由关联至当前顶点的边构成的子序列,满足以下条件:

(i)不存在遍历超过一次的边,

(ii)在其他边能够遍历的情况下,T中的边不应该被遍历。

(c)迭代结束的条件是到达一个顶点,并且已经没有任何可以访问的关联至该顶点的边。

通过反向访问算法经过的顶点,就是该有向图G的欧拉回路。

算法有效性证明:

NULL

算法:

CV:当前顶点;

Av:定义为集合{vi|(vi
, v)∈E};

I(v):表示Av的索引;

其中定义一种运算符T:T((vi , vj))←if
(vi , vj)∈T
then true else false(即判断边是否存在于spanning out-tree,是则真,否则假)

    1. Find
      a spanning out-tree T of G=(V,E) rooted
      at u,

    2. for every vertex
      vV
      do // 初始化


    3. begin


    4. Av


    5. I
      (v)←0


    6. end

    7. for every
      edge(vi , vj)∈E do // 关联至vj的每一条边,如果属于T的边将放在Av的后面最后访问


    8. if
      T((vi , vj))
      then add vi to the tail of Avj


    9. else
      add vi to the head of
      Avj

    10. EC

    11. CVu

    12. while
      I(CV)≤d-(CV) do // 保证了定理中(b)规则


    13. begin

    14. add
      CV to the head of EC // 反向访问遍历的顶点即为欧拉回路,所以每次访问过的顶点放头部


    15. I
      (CV)←I(CV)+1


    16. CV
      ACV(I(CV))


    17. end

    18. Output
      EC

通过借助图的例子进行算法的演算过程:






















Av1

{v2,u}

d-(v1)=2

Av2

{v3,v1}

d-(v2)=2

Av3

{v4,u}

d-(v3)=2

Av4

{v1,v3}

d-(v4)=2

Au

{v2,v4}

d-(u)=2










































































































Iteration

CV

I(u)

I(v1)

I(v2)

I(v3)

I(v4)

0

u

0

0

0

0

0

1

v2

1

0

0

0

0

2

v3

1

0

1

0

0

3

v4

1

0

1

1

0

4

v1

1

0

1

1

1

5

v2

1

1

1

1

1

6

v1

1

1

2

1

1

7

u

1

2

2

1

1

8

v4

2

2

2

1

1

9

v3

2

2

2

1

2

10

u

2

2

2

2

2

11

---

3

2

2

2

2

EC =
{u,v3,v4,u,v1,v2,v1,v4,v3,v2,u}

算法复杂度:

O(|E|)

四、中国邮递员问题

邮递员派信的街道是边赋权连通图。从邮局出发,每条街道至少行走一次,最终回到邮局,如何行走,使其行走的路线最小?

思考1:如果邮路本身是欧拉图,那么通过前述的算法可得行走路线。

思考2:如果邮路不是欧拉图,那么为了得到行走的路线,必须重复行走一些街道。问题转化为如何选取重复行走的街道?

在解决中国邮递员的问题前,我们先计算一下在欧拉图中会存在多少种不同的欧拉回路。

1.#欧拉回路?

对于有向图,可以根据spanning
out-tree计算欧拉图的个数。

定理:在一个连通平衡的有向图G中存在不同的欧拉回路的个数等于:

其中,T(G)是给定的顶点作为根节点的spanning
out-tree的个数。

2.无向图的中国邮递员问题

首先判断图G=(V,E)是否满足存在欧拉回路的条件,即当且仅当图是连通图且奇点的个数为0。

如果满足条件,则通过弗罗莱(Fleury)算法找到的欧拉回路即为中国邮递员问题的一个解。

如果不满足,则必须允许存在重复行进的边。至少有两个奇点,其关联的边会被行进至少两次。重复的边可以经过偶点,最终只可以在奇点处终止,通过在图G=(V,E)中添加重复的边,构成欧拉图G``,即可寻找欧拉回路。

中国邮递员问题转变为寻找这些重复的路径并使得他们的权重和最小。

算法(无向非欧拉图的中国邮递员问题算法):

    1. 在图G中找到连通所有奇点的最短路径;(最短路径算法)

    2. 1中的所有奇点的最短路径构成图G`;

    3. 在G`中找到最小权完美匹配;(最小权完美匹配算法)

    4. 构造欧拉图G``;

    5. 在欧拉图G``中寻找欧拉回路,则该回路即为图G的邮递员回路。

算法演算:

1.奇点{v1,v2,v3,v4},找最小路径;

2.构造G`
























路径权重

最短路径

d(v1,v2)=4

(v1,u2,u3,v2)

d(v1,v3)=5

(v1,u2,u5,v3)

d(v1,v4)=2

(v1,u1,v4)

d(v2,v3)=3

(v2,u4,v3)

d(v2,v4)=5

(v2,u3,u2,u6,v4)

d(v3,v4)=3

(v3,v4)

3.在图G`中找最小权的完美匹配

匹配(Match)图G=(V,E),如果M是边E的子集,且M中的任意两条边都不与同一个顶点相关联,则称M是G的一个匹配。

最大匹配(Maximum Match)最大匹配问题是要找出E的一个子集M,使其具有最大数量的不交迭边,即在M中任何两条边没有一个共同顶点。

完美匹配(Perfect Match)完美匹配是一个包括了图G中原来的所有顶点的匹配。

最大权的完美匹配:对于具有权重的图,求得的完美匹配的权重最大。

在图G`中找最小权的完美匹配,则可以将G`中的边的权重变号,或者设定M并且M大于所有的边的权重d(u,v),再令每条边的权重等于M-d(u,v),再基于算法求G`的最大权完美匹配。

图G`的最小权完美匹配是(v1,v4)和(v2,v3)。如图:

4.构造欧拉图G``

在图G中添加由图G`的最小权完美匹配,此时图G``为欧拉图,如图红边为添加的路径:

5.在图G``中寻找欧拉回路

根据无向图中寻找欧拉回路的方法,找到以v1作为起点的一种欧拉回路为

{v1,u1,v4,v3,u4,v2,v1,u2,u3,v2,u4,u3,u5,v3,u4,u1,v4,u6,u5,u2,u6,u1,v1}

3.有向图的中国邮递员问题

首先判断有向图G=(V,E)是否满足存在欧拉回路的条件,即当且仅当图是连通图且平衡。如果满足条件,则通过上面叙述的方法找到的欧拉回路即为中国邮递员问题的一个解。

这里讨论的是非欧拉的有向图的邮递员回路,对于菲欧拉的无向图来说,任何连通的图都会存在中国邮递员的解,但是对于非欧拉的有向图来说不一定存在解,如图:

明显,当从{v1,v2,v3}任一个顶点访问{u1,u2,u3},邮递员同志就再也回不去{v1,v2,v3}了。非欧拉的有向图存在邮递员回路的条件如下:

定理:一个有向图存在邮递员回路,当且仅当图是强连通图。

证明:NULL

对于非欧拉的无向图来说,至少有两个奇点,其关联的边会被行进至少两次。那么对于非欧拉的有向图,重复行进的边与出度和入度不相等的顶点相关联

定义顶点u,有:

如果D(u)>0,即关联于顶点u的边比关联至u的边要少(出去的要比进来的要少),那么将会有D(u)条重复的边从顶点u出发(让多进来的找多条路出去);如果D(u)<0,即关联至顶点u的边比关联于顶点u的边要少(进来的要比出去的要少),那么将会有-D(u)条重复的边进入顶点u(出去的凑不够就找多些来凑数)。

定义在两个顶点间重复的边的个数为r(u,v),其权重为d(u,v),那么非欧拉有向图的中国邮递员问题转换为优化问题:

 
  运用流的知识解决这个问题
。对于D(u)>0的顶点u可以看作是源点(source),D(u)<0的顶点u可以看作是汇点(sink)。怎么去理解这种问题的转变呢?只要看一下流的概念就马上明白了。

首先要知道,对于任何的有向图,必有:

每一个从源点u到汇点v的流就代表了从u到v的一次重复路径,我们希望从源点u送+D(u)个流到需要汇集-D(v)个流的汇点v,当然每条路径上有权重,那么这些流所经过的最小的权重就能够满足,这也就是最小费用最大流问题。

对于多源点和汇点的最大流问题,可以等效为单源点和单汇点的问题。令单源点为X,每条从X到源点u的边的容量为+D(u)以及权重为0;单汇点为Y,每条从汇点v到Y的边的容量为-D(v)以及权重为0。其他边的容量都设置为无穷大。

算法(有向非欧拉图的中国邮递员问题算法):

    1. 在原图G的基础上加上源点X和汇点Y(前面对X和Y有所叙述),构造图G`;

    2. 在图G`中找到最小费用最大流;

    3. 构造图G``;

    4. 在欧拉图G``中找到欧拉回路,即为图G的最小权重邮递员回路。

算法演算:

1.在图G中计算每一个顶点u的D(u),找到源点和汇点
























 

D(v)

v1

-1

v2

0

v3

2

v4

1

v5

-2

其中,以v1,v5为汇点,v3,v4为源点,加上单源点X和单源点Y构成图G`。

2.在图G`中找到最小费用最大流





c(X,v3)=c(v5,Y)=2

c(X,v4)=c(v1,Y)=1

对于其他边(u,v)

c(u,v)=∞

图中最小费用最大流如图所示,其中图中边的数字表示——权重/可行流/容量。从图中,路径(X,v3,v4,v5,Y)有两个单位的可行流,路径(X,v4,v5,v1,Y)有一个单位的可行流。那么重复路径为两条(v3,v4,v5),一条(v4,v5,v1)。

3.根据(2)的结果构造G``

4.从欧拉图G``中寻找欧拉路径,即为有向图G的邮递员问题的一个解

其中的一个解为(v1,v2,v3,v4,v5,v2,v4,v5,v3,v4,v5,v1,v3,v4,v5,v1)。

五、总结

欧拉图和中国邮递员问题是图论中古老的问题,涉及到图论的很多知识。

      1. 最短路径问题

      2. 寻找欧拉回路问题

      3. 最大权完美匹配问题

      4. 最小费用最大流问题

      5. 中国邮递员问题

六、参考

演算法筆記:http://www.csie.ntnu.edu.tw/~u91029/

匹配:http://www.csie.ntnu.edu.tw/~u91029/Matching.html

回路:http://www.csie.ntnu.edu.tw/~u91029/Circuit.html#2

路径:http://www.csie.ntnu.edu.tw/~u91029/Path.html

流:http://www.csie.ntnu.edu.tw/~u91029/Flow2.html#8

一份老师给的某本图论书第六章的资料,估计应该是Alan.M.
Gibbons写的Algorithmic Graph
Theory

2014-05-20

时间: 2024-08-29 09:25:13

欧拉图与中国邮递员问题算法的相关文章

OI省选算法汇总

copy from hzwer @http://hzwer.com/1234.html 侵删 1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.

[转]省选算法总结

1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏树 *配对堆

OI算法汇总[大纲]

1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 7.可并堆 左偏树 *配对堆

[转]OI省选算法汇总

简单列了一点 1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏

[转]省选算法汇总

1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏树 *配对堆

acm算法总结zon列表

简单列了一点 1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏

省选必知

简单列了一点 1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏

要学的东西...

1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 1.2 中级数据结构 1. 堆 2. 并查集与带权并查集 3. hash 表 自然溢出 双hash 1.3 高级数据结构 1. 树状数组 2. 线段树,线段树合并 3. 平衡树 Treap 随机平衡二叉树 Splay 伸展树 * Scapegoat Tree 替罪羊树 4. 块状数组,块状链表 5.* 树套树 线段树套线段树 线段树套平衡树 * 平衡树套线段树 6.可并堆 左偏树 *配对堆

算法问题整理

1.相同位数,数字和相同问题 给定一个数字编码N,大多数情况下可以找到一个数字编码M,其位数与N相同,各位数字之和与N的各位数字之和相同.并且M是大于N的数值中最小的一个,也可能M不存在.如:N=134,则M=143.如N=020,则M=101.形式化表述为F(N)=M.如果M不存在,则F(N)=-1.要求给定算法计算F(N)序列. #include<iostream> #include<cstring> using namespace std; #define MAXNUM 10