zoukankan      html  css  js  c++  java
  • 欧拉图的判定欧拉路的求法

    其中 dfs 的代码 主要来自: https://blog.csdn.net/Jaster_wisdom/article/details/51067234

    一,前言

    这里讲的都是无向图,没讲有向的。

    其中,如果 无向图没有奇数度结点,则具有欧拉回路,是欧拉图

               如果 无向图有两个奇数度结点,则仅有欧拉通路,是半欧拉图

               此外,则该无向图既不是欧拉图也不是半欧拉图

    测试数据的图:

    二,Fleury 算法

    1, 算法思想

    选取起点,其中欧拉图的起点任意,半欧拉图的起点从 两个奇度结点中的任意一个 开始。

    然后从起点依次选边,每选一条边就从图中删去。选取条件是:① 与上一条已选取的边关联;② 除非无别的边可 选,否则不能选割边(桥)。

    2,步骤

     ① 判断该图是什么图

     ② 选择起点 

     ③  删边

     ④ 将删除的边 加入  欧拉路中

     ⑤ 循环 ③ ④,直至 无边 可删

    3,代码

    #define _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define N 1000
    int a[N][N];   //邻接矩阵
    int n, m;   // n 点数 , m 边数
    int judge_bridge(int i)   // 通过判断以 i 为终点的边 是否 只有一个,来判断这条边是否是 割边
    {
        int cnt = 0;
        for (int j = 0; j < n; j++)
        {
            if (a[i][j])
                cnt++;
        }
        if (cnt == 1)
            return 0;
        return 1;
    }
    void Fleury(int cur)  // cur 为起点
    {
        int t = 0;  // 记录割边的终点
        int f3 = 0;   // 标记 第一条边
        while (1)
        {
            int f1 = 0;  // 标记 是否有找到 正常边
            int f2 = 0;   // 如果有 割边,记录 第一条割边
            for (int j = 0; j < n; j++)
            {
                if (a[cur][j])
                {
                    if (judge_bridge(j))   // 如果这条边不是割边,则删除这条边
                    {
                        f1 = 1;
                        a[cur][j] = 0;
                        a[j][cur] = 0;
                        printf(f3 == 0 ? "(%d,%d)" : "->(%d,%d)", cur, j);
                        f3 = 1;
                        cur = j;
                        break;
                    }
                    if (judge_bridge(j) == 0 && f2 == 0)   // 记录可能出现的割边,以备不时之需
                    {
                        f2++;
                        t = j;
                    }
                }
            }
            if (f1 == 0 && f2 == 1)    // 到了不选割边不行的地步了
            {
                a[cur][t] = 0;
                a[t][cur] = 0;
                printf(f3 == 0 ? "(%d,%d)" : "->(%d,%d)", cur, t);
                f3 = 1;
                cur = t;
            }
            if (f1 == 0 && f2 == 0)   // 无边可选,邻接矩阵空了,算法结束
            {
                puts("");
                break;
            }
        }
    }
    void creat()   // 直接 输入邻接矩阵
    {
        for (int i = 0; i < n; i++)//使用邻接矩阵表示图 
        {
            for (int j = 0; j < n; j++)
            {
                scanf("%d", &a[i][j]);
            }
        }
    }
    void judge()
    {
        int odd = 0;   // 存奇数度数 的个数
        int flag = 0;  // 存 奇度边  的编号,如果是 半欧拉图 就从 奇度边 出发,若是 欧拉回路,就随便从 0 开始
        for (int i = 0; i < n; i++)
        {
            int cnt = 0;
            for (int j = 0; j < n; j++)  // 统计每个结点的 度数
                cnt += a[i][j];
            if (cnt % 2)    // 若为 奇数,总数 +1
            {
                flag = i;
                odd++;
            }
        }
        if (odd == 0)
        {
            printf("判定:该无向图没有奇数度结点,具有欧拉回路,是欧拉图
    ");
            printf("欧拉回路为:");
            Fleury(flag);
        }
        else if (odd == 2)
        {
            printf("判定:该无向图有两个奇数度结点,仅有欧拉通路,是半欧拉图
    ");
            printf("欧拉通路为:");
            Fleury(flag);
        }
        else
            printf("判定:该无向图既不是欧拉图也不是半欧拉图
    ");
    }
    int main(void)
    {
        while (scanf("%d", &n) != EOF)   // 输入结点数   尝试了一下就 234 会有 欧拉路
        {
            memset(a, 0, sizeof(a));
            creat();  // 直接 输入邻接矩阵
            judge(); // 判断 该 邻接矩阵 是什么图,若有欧拉路 则输出 路径
        }
    
        system("pause");
        return 0;
    }
    /*
    测试数据1:欧拉回路
    7
    0 1 0 0 1 0 0
    1 0 1 1 1 0 0
    0 1 0 1 0 0 0
    0 1 1 0 1 0 1
    1 1 0 1 0 1 0
    0 0 0 0 1 0 1
    0 0 0 1 0 1 0
    测试数据2:欧拉通路
    5
    0 1 1 0 0
    1 0 1 1 1
    1 1 0 1 1
    0 1 1 0 1
    0 1 1 1 0
    */
    View Code

    三,DFS

    1,个人感觉,不知对错

    ① 这里面虽然没有判断割边,但是判断了孤立点,它用深搜进行删边,这里的深搜只进行搜索删边,并没有回溯。

    但是它将结点压入栈中了,然后再通过 栈中的结点 进行回溯,将孤立点加入通路中。那没什么存下来的路径不是散乱的点呢? 

    ② 我们要明白一个前提就是这是个 欧拉图 或者是 半欧拉图,如果是从起点开始搜索的话,是有可能一次搜完的。

    那什么时候会出现几条路径呢,只有它在有其他的路可选的情况下,搜索了割边。

    ③ 我猜测如果搜索的是割边的话,那么剩余图一定是回路(因为画了好几次都是这样,也不会证明,不知道对不对 ┌(; ̄◇ ̄)┘) 

    所以在我们通过 栈 里面的 结点 进行回溯时,在中间对剩余图进行再次深搜,就相当于在原通路中插入一条回路,仍然还是一条通路。

    这样才能存下来的路径不是散乱的点 

    2,代码

    #define _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<stack>
    using namespace std;
    #define N 1000
    int map[N][N], way[N];
    stack<int>s;
    int n, m;  // 点数 边数
    void  dfs(int k)
    {
        s.push(k);
        for (int i = 0; i < n; i++)   // 一条路 删到没路 不管有无割边
        {
            if (map[k][i])
            {
                map[i][k] = map[k][i] = 0;
                dfs(i);
                break;
            }
        }
    }
    void Fleury(int k)
    {
        stack<int>ss; s = ss;  // 栈的清空
    
        int cnt = 0;
        s.push(k);  // 起点入栈
        while (s.size())
        {
            int vertex = s.top();
            s.pop();
    
            int flag = 0;
            for (int i = 0; i < n; i++)  // 通过判断 与vertx 相邻的边的个数 来判断是否 这点是否 是孤立点
            {
                if (map[vertex][i] > 0)   // 只要有边 就可以删
                {
                    flag = 1;
                    break;
                }
            }
    
            if (flag == 0)   // 该点是 孤立点
                way[cnt++] = vertex;
            else           // 不是孤立点 可以继续 删边        
                dfs(vertex);
        }
        for (int i = cnt - 1; i > 0; i--)  // 打印路径
            printf("%d->", way[i]);
        printf("%d
    ", way[0]);
    }
    void judge()
    {
        int odd = 0;   // 存奇数度数 的个数
        int flag = 0;  // 存 奇度边  的编号,如果是 半欧拉图 就从 奇度边 出发,若是 欧拉回路,就随便从 0 开始
        for (int i = 0; i < n; i++)
        {
            int cnt = 0;
            for (int j = 0; j < n; j++)  // 统计每个结点的 度数
                cnt += map[i][j];
            if (cnt % 2)    // 若为 奇数,总数 +1
            {
                flag = i;
                odd++;
            }
        }
        if (odd == 0)
        {
            printf("判定:该无向图没有奇数度结点,具有欧拉回路,是欧拉图
    ");
            printf("欧拉回路为:");
            Fleury(flag);
        }
        else if (odd == 2)
        {
            printf("判定:该无向图有两个奇数度结点,仅有欧拉通路,是半欧拉图
    ");
            printf("欧拉通路为:");
            Fleury(flag);
        }
        else
            printf("判定:该无向图既不是欧拉图也不是半欧拉图
    ");
    }
    int main(void)
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++)
        {
            int x, y; scanf("%d%d", &x, &y);
            map[x][y] = map[y][x] = 1;
        }
        judge();
    
    
        system("pause");
        return 0;
    }
    /*
    测试数据1:欧拉回路
    7 10
    0 1
    0 4
    1 2
    1 4
    1 3
    2 3
    3 4
    4 5
    5 6
    6 3
    测试数据2:欧拉通路
    5 8
    0 1
    0 2
    1 2
    1 3
    1 4
    2 3
    2 4
    3 4
    */
    View Code

    =========== ========= ======== ======= ====== ===== ==== === == =

    哪里会有人喜欢孤独,只是不喜欢失望罢了。

                     —— 村上春树

  • 相关阅读:
    307. Range Sum Query
    OLI 课程 & Java入学考试的五道题
    745. Prefix and Suffix Search 查找最大index的单词
    38.Count and Say 报数
    721. Accounts Merge合并电子邮件账户
    265. Paint House II 房子涂色K种选择的版本
    【转】如何做人性化的代码审查?从高到低、用例子
    java之struts2之文件下载
    java之struts2之文件上传
    java之struts2之拦截器
  • 原文地址:https://www.cnblogs.com/asdfknjhu/p/13081167.html
Copyright © 2011-2022 走看看