首页 > 代码库 > Fleury 欧拉回路
Fleury 欧拉回路
基本概念
(1)定义
欧拉通路 (欧拉迹)—通过图中每条边一次且仅一次,并且过每一顶点的通路。
欧拉回路 (欧拉闭迹)—通过图中每条边一次且仅一次,并且过每一顶点的回路。
欧拉图—存在欧拉回路的图。欧拉图就是从一顶出发每条边恰通过一次又能回到出发顶点的那种图,即不重复的行遍所有的边再回到出发点。
通路和回路-称vie1e2…envj为一条从 vi到 vj且长度为n的通路,其中长度是指通路中边的条数.称起点和终点相同的通路为一条回路。
简单图-不含平行边和自回路的图。
混合图-既有有向边,也有无向边的图
平凡图-仅有一个结点的图
完全图-有n个结点的且每对结点都有边相连的无向简单图,称为无向完全图;有n个结点的且每对结点之间都有两条方向相反的边相连的有向简单图为有向完全图。
(2)欧拉图的特征:
无向图
a)G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。
b)G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点。
有向图
a)D有欧拉通路:D连通,除两个顶点外,其余顶点的入度均等于出度,这两个特殊的顶点中,一个顶点的入度比出度大1,另一个顶点的入度比出度小1。
b)D有欧拉回路(D为欧拉图):D连通,D中所有顶点的入度等于出度。一个有向图是欧拉图,当且仅当该图所有顶点度数都是0。
判断方法
一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。
有向图存在欧拉回路的充要条件
一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图。
混合图存在欧拉回路条件
要判断一个混合图G(V,E)(既有有向边又有无向边)是欧拉图,方法如下:
假设有一张图有向图G‘,在不论方向的情况下它与G同构。并且G‘包含了G的所有有向边。那么如果存在一个图G‘使得G‘存在欧拉回路,那么G就存在欧拉回路。
Knowledge
弗罗莱(Fleury)算法思想-解决欧拉回路
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)不能再进行时,算法停止。
可以证明,当算法停止时所得的简单回路Wm=v0e1v1e2….emvm(vm=v0)为G中的一条欧拉回路,复杂度为O(e*e)。
简单理解
对于欧拉图,从一个节点出发,随便往下走(走过之后需要标记一下,下次就不要来了),必然也在这个节点终止(因为除了起始节点,其他节点的度数都是偶数,只要能进去就能出来)。这样就构成了一个圈,但因为是随便走的,所以可能会有些边还没走过就回来了。我们就从终止节点逆着往前查找,直到找到第一个分叉路口,然后从这个节点出发继续上面的步骤,肯定也是可以找到一条回到这个点的路径的,这时我们把两个圈连在一起。当你把所有的圈都找出来后,整个欧拉回路的寻找就完成了。寻找欧拉回路时,起始节点是可以任意选择的。如果是有基度顶点要寻找欧拉通路,则从基度顶点出发就好了,上述步骤依然有效。
常用结论
- 无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数);
- 无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点;
- 有向连通图D是欧拉图,当且仅当该图为连通图且D中每个结点的入度=出度
- 有向连通图D含有欧拉通路,当且仅当该图为连通图且D中除两个结点外,其余每个结点的入度=出度,且此两点满足deg-(u)-deg+(v)=±1。(起始点s的入度=出度-1,结束点t的出度=入度-1 或两个点的入度=出度)
- 一个连通且每个顶点的度数都为偶数的图一定没有割边
- 存在欧拉路的条件:图是连通的,有且只有2个奇点.
- 存在欧拉回路的条件:图是连通的,0个奇点.
模板
#include<bits/stdc++.h>#define IN inline#define RG registerusing namespace std;struct Fleury{ static const int N=1010,M=N<<2; int n,m;int f[N],d[N]; set<int>s[N];vector<pair<int,int> >ans; IN void dfs(RG int x){//随意从一个点调入 while(s[x].size()){ RG int p=*s[x].begin(); s[x].erase(p);s[p].erase(x); ans.push_back(make_pair(x,p));dfs(p); } }//判是否为欧拉图 连通+(入度=出度) IN void pri(){printf("No");exit(0);} IN int find(int x){return x==f[x]?x:f[x]=find(f[x]);} IN void pan_n(){//无向图 set<int>::iterator it; for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=n;i++) for(it=s[i].begin();it!=s[i].end();it++) if(find(i)!=find(*it))f[f[i]]=f[*it]; int fa=f[1]; for(int i=1;i<=n;i++)if(f[i]!=fa||s[i].size()&1)pri(); } IN void pan_y(){//有向图 set<int>::iterator it; for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=n;i++) for(it=s[i].begin();d[*it]++,it!=s[i].end();it++) if(find(i)!=find(*it))f[f[i]]=f[*it]; int fa=f[1]; for(int i=1;i<=n;i++)if(f[i]!=fa||(int)s[i].size()!=d[i])pri(); }}ou;
Practice
Codeforces Round #375 (Div. 2)E. One-Way Reform
NYOJ42 一笔画问题
Fleury 欧拉回路