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)

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

常用结论

  1. 无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数);
  2. 无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点;
  3. 有向连通图D是欧拉图,当且仅当该图为连通图且D中每个结点的入度=出度
  4. 有向连通图D含有欧拉通路,当且仅当该图为连通图且D中除两个结点外,其余每个结点的入度=出度,且此两点满足deg-(u)-deg+(v)=±1。(起始点s的入度=出度-1,结束点t的出度=入度-1 或两个点的入度=出度)
  5. 一个连通且每个顶点的度数都为偶数的图一定没有割边
  6. 存在欧拉路的条件:图是连通的,有且只有2个奇点.
  7. 存在欧拉回路的条件:图是连通的,0个奇点.

模板

#include<bits/stdc++.h>
#define IN inline
#define RG register
using 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 一笔画问题

时间: 2024-07-30 10:08:05

Fleury 欧拉回路的相关文章

【欧拉回路】【欧拉路径】【Fleury算法】CDOJ1634 记得小苹初见,两重心字罗衣

Fleury算法看这里 http://hihocoder.com/problemset/problem/1181 把每个点看成边,每个横纵坐标看成一个点,得到一个无向图. 如果新图中每个点的度都是偶数,那么就是一个欧拉图,对该图跑一遍欧拉回路,对走过的边轮流染色,就可以保证每个点所连的边的红蓝颜色相等. 如果存在度数为奇数的点,新建两个点a和b.把横坐标的度数为奇数的点和a连边,把纵坐标为奇数的点和b连边,这样最多只有a和b的度数为奇数,可以跑欧拉路径. 注意Fleury算法的时候,要及时把访问

【欧拉回路】【Fleury算法】CDOJ1642 老当益壮, 宁移白首之心?

题意: 构造一个01串,使得满足以下条件: 1. 环状(即首尾相连) 2. 每一位取值为0或1 3. 长度是2^n 4. 对于每个(2^n个)位置,从其开始沿逆时针方向的连续的n位01串(包括自己) 构成的数均不相同,即0到2^n?1中的数各出现一次 数据范围: 1<=n<=15 欧拉回路 考虑用一条边表示一个数,那么题目要求就是无重复的遍历完所有边, 则这是一个欧拉图的问题. 对于有公共点的两条边,第一个的后n-1位和第二个的前n-1相同. 这样将一条边的前n-1位和后n-1位作为点,连边,

欧拉回路&amp;Fleury算法&amp;实现

基本知识 欧拉回路:图G,若存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路,如果存在一条回路经过G每条边有且仅有一次, 称这条回路为欧拉回路.具有欧拉回路的图成为欧拉图. 判断欧拉路是否存在的方法 有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度. 无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的. 判断欧拉回路是否存在的方法 有向图:图连通,所有的顶点出度=入度. 无向图:图连通,所有顶点都是偶数度. 程序实现一般是如下过程: 1.利用并查集判

Fleury(弗罗莱)算法求欧拉回路

转自http://www.cnblogs.com/Lyush/archive/2013/04/22/3036659.html 上面是摘自图论书上的定义. 算法在运行过程中删除了所有已走的路径,也就是说途中残留了所有没有行走的边.根据割边的定义,如果在搜索过程中遇到割边意味着当前的搜索路径需要改进,即提前输出某一个联通子集的访问序列,这样就能够保证访问完其中联通子图中后再通过割边访问后一个联通子图,最后再沿原路输出一开始到达该点的路径.如果只有割边可以扩展的话,只需要考虑先输出割边的另一部分联通子

Fleury算法 求欧拉回路

Fleury算法 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <climits> 7 #include <vector> 8 #include <queue> 9 #include <cstdlib> 10 #in

SCU 4520 Euler 欧拉回路

Euler Time Limit:0MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description Time Limit: 1000 MS              Memory Limit: 256 M 给出一幅n个点,m条边的图,分别判断该图是无向图和有向图条件下,是否存在欧拉通路. 输入 输入包含多组数据.第一行为一个整数T(1?≤?T?≤?100),代表数据组数,对于每组数据: 第一行是两个整数n和m( 1?≤?n?

poj 1780 , poj 1392 欧拉回路求前后相互衔接的数字串

两道题目意思差不多 第一题是10进制 , 第二题是2进制的 都是利用欧拉回路的fleury算法来解决 因为我总是希望小的排在前面,所以我总是先将较小数加入栈,再利用另一个数组接收答案,但是这里再从栈中导出来答案要倒一下了,这一点要注意 poj 1780 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 using namespace std; 5 #define N 1000010 6 7 int

The Necklace UVA 10054 (无向图的欧拉回路,求证Flury算法)

说说:题目的意思本质上就是给你N条无向边,若存在欧拉回路,则将其生成.无向图的欧拉回路的判断非常容易,只要判断是否每个节点都是偶数度即可.但是,对欧拉回路的生成,也就是Fleury算法,貌似有点问题.我自己在这个地方也纠结了好久.下面就来讲讲Fleury算法. 开始我觉得,就是个非常简单的深度优先搜索的问题,直接从任意一个节点,然后不断DFS即可.所以就有了如下的代码: for(i=1;i<MAX;i++) if(map[m][i]>0){ map[m][i]--; map[i][m]--;

2017年 1月15日 欧拉回路 学习整理

欧拉回路 欧拉通路: 通过图中每条边且只通过一次,并且经过每一顶点的通路(顶点并不要求都应经过一遍) 欧拉回路: 通过图中每条边且只通过一次,并且经过每一顶点的回路 有向图的基图:忽略有向图所有边的方向,得到的无向图称为该有向图的基图. 无向图 设G是连通无向图,则称经过G的每条边一次并且仅一次的路径为欧拉通路: 如果欧拉通路是回路(起点和终点是同一个顶点),则称此回路是欧拉回路 具有欧拉回路的无向图G成为欧拉图 有向图 (1)设D是有向图,D的基图连通,则称经过D的每条边一次并且仅有一次的有向