欧拉回路&Fleury算法&实现

基本知识

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

称这条回路为欧拉回路。具有欧拉回路的图成为欧拉图。

判断欧拉路是否存在的方法

有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度。

无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的。

判断欧拉回路是否存在的方法

有向图:图连通,所有的顶点出度=入度。

无向图:图连通,所有顶点都是偶数度。

程序实现一般是如下过程:

1.利用并查集判断图是否连通,即判断p[i] < 0的个数,如果大于1,说明不连通。

2.根据出度入度个数,判断是否满足要求。

3.利用dfs输出路径。

考虑一个比较有意思的问题,单词连接问题。

样例

考虑一个比较有意思的问题,单词连接问题。

给出n个单词,如果一个单词的尾和另一个单词的头字符相等,那么可以相连,问这n个单词是否可以排成一列。

这个显然可以使用欧拉路问题进行解决。考虑每一个单词的第一个字母入度加1,每一个单词的最后一个字母出度加1,然后每一个单词都相当于一条有向边,这样就可以利用这些信息进行是否联通的判断,比较高效的策略是使用并查集进行判断。

实现代码如下:

#include <iostream>
#include <assert.h>
#include <string>
using namespace std;

const int maxv = 27;
int in[maxv];
int out[maxv];
int p[maxv];
int rankk[maxv];
int used[maxv];
void init()
{
   for(int i=0;i<maxv;i++)
   {
      p[i] = i;
      in[i] = 0;
      out[i]=0;
      rankk[i] =1;
   }
}
int find(int a)
{
    if(p[a]==a)
      return p[a];
    p[a] = find(p[a]);
    return p[a];
}

bool unions(int a,int b)
{
    int pa = find(a),pb = find(b);
    if(pa==pb)
      return false;
    if(rankk[pa]>rankk[pb])
    {
        p[pb]=pa;
        rankk[pa]+=rankk[pb];
    }
    else
    {
        p[pa] = pb;
        rankk[pb]+=rankk[pa];
    }
    return true;
}
int main(int argc,char* argv[])
{
    init();
    int wordCount = 0;
    cin>>wordCount;
    string word;
    while(wordCount>0)
    {
       cin>>word;
       int len = word.size();
       in[word[0]-'a']++;
       out[word[len-1]-'a']++;
       used[word[0]-'a'] = 1;
       used[word[len-1]-'a'] = 1;
       unions(word[0]-'a',word[len-1]-'a');
       wordCount--;
    }
    int scc = 0;
    for(int i=0;i<maxv;i++)
    {
        if(used[i]&&p[i]==i)
        {
             scc++;
             //break;
        }
    }
    cout<<scc<<endl;
    assert(scc<=1);
    if(scc>1)
    {
       cout<<"scc is greater than 1 so it is not ok exit"<<endl;
       return -1;
    }
    int a=0,b=0;
    for(int i=0;i<maxv;i++)
    {
       if(!used[i])
          continue;
       cout<<'a'+i<<" "<<in[i]<<" "<<out[i]<<endl;
       if(in[i]==out[i])
         continue;
       if(in[i]-out[i]==1)
          a++;
       else if(in[i]-out[i]==-1)
          b++;
       else
      {
           cout<<"not ok,exit"<<endl;
           return -1;
       }
    }
    if((a==1&&b==1)||a+b==0)
      cout<<"OK"<<endl;
    return 0;
}

Fleury算法

对于有向图和无向图都可以使用Fleury算法累实现寻找欧拉回路问题。下面介绍一下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)

//
//  Eular.h
//  HelloWorld
//
//  Created by jackqiu on 15-1-5.
//  Copyright (c) 2015年 jackqiu. All rights reserved.
//

#ifndef HelloWorld_Eular_h
#define HelloWorld_Eular_h
class Eular
{
private:
#define SIZE 1000
    int graph[SIZE][SIZE];
    int stack[SIZE+10];
    int top;//the
    int size;
    /**
     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)。
     */
    void DFS(int x,int t)
    {
        stack[++top] = x;
        int brige = 0,i;
        for(i=t;i<size;i++)
        {
            if(graph[x][i])
            {
                graph[x][i] = graph[i][x] = 0;
                brige = 1;
                DFS(i,0);
                break;
            }
        }
        if(brige==0)//没有边的话就往后退
        {
            int beforeX = stack[--top];//相当于先pop,然后取栈顶的元素
            graph[beforeX][x] = graph[x][beforeX] = 1;//回复刚刚的数据,返回的上一个节点
            if(top== size)
            {
                stack[++top] = x;
            }
            else
            {
                top--;
                DFS(beforeX,x+1);//visit the next node of x
            }
        }
    }
public:
    Eular()
    {

    }
    void eular()
    {
        cout<<"please input the size:";
        cin>>size;
        cout<<"input the edge for example 1 2  (-1 -1) to exit"<<endl;
        int a,b;
        cin>>a>>b;
        graph[a][b] = graph[b][a] = 1;
        while(a!=-1&&b!=-1)
        {
            cin>>a>>b;
            graph[a][b] = graph[b][a] = 1;
        }
        top = 0;
        DFS(0,0);
        for(;top>0;top--)
        {
            cout<<stack[top]<<" ";
        }
        cout<<endl;
    }
};

#endif

时间: 2024-08-04 16:58:28

欧拉回路&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位作为点,连边,

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

codeforces 508 D. Tanya and Password (fleury算法)

codeforces 508 D. Tanya and Password (fleury算法) 题目链接: http://codeforces.ru/problemset/problem/508/D 题意: 给出n个长度为3的字符串,如:abc bca aab 如果一个字符串的长度为2的后缀等于,另外一个字符串的长度为2的前缀,则这两个字符串能连起来,比如:aabca,然后这n个字符串可以形成一个图,求图上的一条欧拉通路. 限制: 1 <= n <= 2*10^5,字符串里面有大写字母,小写字

hihoCoder - 1181 - 欧拉路&#183;二 (Fleury算法求欧拉路径)

#1181 : 欧拉路·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回中小Hi和小Ho控制着主角收集了分散在各个木桥上的道具,这些道具其实是一块一块骨牌. 主角继续往前走,面前出现了一座石桥,石桥的尽头有一道火焰墙,似乎无法通过. 小Hi注意到在桥头有一张小纸片,于是控制主角捡起了这张纸片,只见上面写着: 将M块骨牌首尾相连放置于石桥的凹糟中,即可关闭火焰墙.切记骨牌需要数字相同才能连接. --By 无名的冒险者 小Hi和小Ho打开了主角的道具栏,发现

hiho欧拉路&#183;二 ----- Fleury算法求欧拉路径

hiho欧拉路·二 分析: 小Ho:这种简单的谜题就交给我吧! 小Hi:真的没问题么? <10分钟过去> 小Ho:啊啊啊啊啊!搞不定啊!!!骨牌数量一多就乱了. 小Hi:哎,我就知道你会遇到问题. 小Ho:小Hi快来帮帮我! 小Hi:好了,好了.让我们一起来解决这个问题. <小Hi思考了一下> 小Hi:原来是这样...小Ho你仔细观察这个例子: 因为相连的两个数字总是相同的,不妨我们只写一次,那么这个例子可以写成:3-2-4-3-5-1.6个数字刚好有5个间隙,每个间隙两边的数字由

CCF 第六次计算机职业认证 第四题 收货 stl动态存储和fleury算法的综合应用

问题描述 为了增加公司收入,F公司新开设了物流业务.由于F公司在业界的良好口碑,物流业务一开通即受到了消费者的欢迎,物流业务马上遍及了城市的每条街道.然而,F公司现在只安排了小明一个人负责所有街道的服务. 任务虽然繁重,但是小明有足够的信心,他拿到了城市的地图,准备研究最好的方案.城市中有n个交叉路口,m条街道连接在这些交叉路口之间,每条街道的首尾都正好连接着一个交叉路口.除开街道的首尾端点,街道不会在其他位置与其他街道相交.每个交叉路口都至少连接着一条街道,有的交叉路口可能只连接着一条或两条街

简单的Fleury算法模板

假设数据输入时采用如下的格式进行输入:首先输入顶点个数n和边数m,然后输入每条边,每条边的数据占一行,格式为:u,v,表示从顶点u到顶点v的一条有向边 这里把欧拉回路的路径输出了出来: 手写栈: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 #define N 1005 6 int first[N],k,degree[N],visit[N];

求欧拉路径模版 fleury算法

支持多重边,按字典序输出. #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=510; const int INF=1e9+10; int n,m; int G[maxn][maxn]; int stk[maxn*3],t