zoukankan      html  css  js  c++  java
  • 欧拉回路

    欧拉路径:若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路

    图论起源于18世纪,1736年瑞士数学家欧拉(Euler)发表了图论的第一篇论文“哥尼斯堡七桥问题”。在当时的哥尼斯堡城有一条横贯全市的普雷格尔
     
    河,河中的两个岛与两岸用七座桥连结起来。当时那里的居民热衷于一个难题:有游人怎样不重复地走遍七桥,最后回到出发点。 为了解决这个问题,欧拉用A,B,C,D4个字代替陆地,作为4个顶点,将联结两块陆地的桥用相应的线段表示,于是哥尼斯堡七桥问题就变成了图中,是否存在经过每条边一次且仅一次,经过所有的顶点的回路问题了。欧拉在论文中指出,这样的回路是不存在的。
    //欧拉回路
    void euler(int u)
    {
        for(int v = 0; v<n; v++) if(G[u][v]&&vis[u][v])
        {
            vis[u][v] = vis[v][u] = 1;
            euler(v);
            printf("%d %d
    ", u, v);
        }
    } 
    
    //注:G[u][v]为 1 时, 为u和v是连通的, 为 0 不连通 。
    //程序只适用于欧拉道路和欧拉回路, 但是如果要打印的是欧拉道路
    //在主程序中调用时,参数必须是道路的起点, 另外打印的顺序是逆序的
    //因此在真正使用这份代码时应当把printf改成push语句,把(u,v)压入栈 

    《1》单词

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=105&page=show_problem&problem=1070

    分析一下:

    本题主要是把字母看作结点,单词看成有向边,则有解当且仅当图中有欧拉路径。注意要先判连通。 连通如何判断呢? 好无疑问, 并查集。 不用理我, 下面我在吐槽! 哎!感觉自己也不是十分的是个十足的fool 。 然而现在还是停留在能勉强看懂代码的水平上(要费好大的劲才能看懂!)。 不说啦,都是眼泪!。

     1 // 算法:把字母看作结点,单词看成有向边,则有解当且仅当图中有欧拉路径。注意要先判连通
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<vector>
     5 using namespace std;
     6 
     7 const int maxn = 1000 + 5;
     8 
     9 // 并查集(代码摘自《算法竞赛入门经典——训练指南》第三章)
    10 int pa[256];
    11 int findset(int x) { return pa[x] != x ? pa[x] = findset(pa[x]) : x; } 
    12 
    13 int used[256], deg[256]; // 是否出现过;度数
    14 
    15 int main() {
    16   int T;
    17   scanf("%d", &T);
    18   while(T--) {
    19     int n;
    20     char word[maxn];
    21 
    22     scanf("%d", &n);
    23     memset(used, 0, sizeof(used));
    24     memset(deg, 0, sizeof(deg));
    25     for(int ch = 'a'; ch <= 'z'; ch++) pa[ch] = ch; // 初始化并查集
    26 
    27     int cc = 26; // 连通块个数 (最多有26个连通块) 
    28 
    29     for(int i = 0; i < n; i++) {
    30       scanf("%s", word);
    31       char c1 = word[0], c2 = word[strlen(word)-1];
    32       deg[c1]++;                                   //很机智的方法 
    33       deg[c2]--;
    34       used[c1] = used[c2] = 1;                    //表示该字母被用过 
    35       int s1 = findset(c1), s2 = findset(c2);
    36       if(s1 != s2) { pa[s1] = s2; cc--; }          
    37     }
    38 
    39     vector<int> d;
    40     for(int ch = 'a'; ch <= 'z'; ch++) {
    41       if(!used[ch]) cc--;                 //没出现过的字母 
    42       else if(deg[ch] != 0) d.push_back(deg[ch]);
    43     }
    44     bool ok = false;
    45     if(cc == 1 && (d.empty() || (d.size() == 2 && (d[0] == 1 || d[0] == -1)))) ok = true;
    46     if(ok) printf("Ordering is possible.
    ");
    47     else printf("The door cannot be opened.
    ");
    48   }
    49   return 0;
    50 }
    View Code

    代码实现思路:

    代码的难度主要在求连通块的部分。 现在我谈一下我对这一部分的理解。

    首先是连通块最多有 26 个(至于为什么, 很简单, 因为一共有26个小写字母)。合并能合并的连通块, 减去没出现的字母, 就是结果连通块啦。如果唯一(链)或为0(环)就成功啦! 里面牵扯到好多技巧, 请细看代码!

  • 相关阅读:
    关闭编辑easyui datagrid table
    sql 保留两位小数+四舍五入
    easyui DataGrid 工具类之 util js
    easyui DataGrid 工具类之 后台生成列
    easyui DataGrid 工具类之 WorkbookUtil class
    easyui DataGrid 工具类之 TableUtil class
    easyui DataGrid 工具类之 Utils class
    easyui DataGrid 工具类之 列属性class
    oracle 卸载
    “云时代架构”经典文章阅读感想七
  • 原文地址:https://www.cnblogs.com/acm1314/p/4561718.html
Copyright © 2011-2022 走看看