欧拉回路&【洛谷习题】无序字母对

首先非常痛心疾首地说一句,欧拉回路自己之前只是看过代码,知道思想,从来没有亲手实现过,所以,,,伤亡惨重!!!

欧拉回路是一个非常有意思的图论模型,因为伟大的数学家欧拉(euler)而得名。传说,曾经人们沉迷于一个七桥问题,想找出一种走法不重复地经过七座桥(具体请自行了解)。欧拉指出了不存在这样的走法,并由此归结出了“一笔画问题”。用图论的语言来说,就是找一条路径不重复地走过所有的边。

实际上,从一个点出发,不重复地经过所有的边,这叫做欧拉道路;如果这条路径起点和终点相同,才称为欧拉回路。另外,如果一个图存在欧拉道路,那么称为半欧拉图,如果一个图存在欧拉回路,称为欧拉图。

对于无向图,存在欧拉道路的条件是只有两个或不存在奇点(度为奇数的点),存在欧拉回路的条件是不存在奇点。对于有向图,存在欧拉道路的条件是只有两个点的入度和出度不相同,并且其中一个点(起点)的出度比入度大1,另一个点(终点)的入度比出度大1,或者所有点的入度和出度都相等,存在欧拉回路的条件是所有点的入度和出度都相等。当然图必须是连通的。

寻找欧拉道路或者欧拉回路是比较简单的,可以使用DFS。起点的确定也需要注意,如果找欧拉道路,必须找到相应的起点,而欧拉回路任选一个点作为起点即可。

1 void euler(int u) {
2     for(int v=1;v<=n;++v)
3         if(G[u][v]) {
4             G[u][v]=G[v][u]=0; //有向图则改为G[u][v]=0;
5             euler(v);
6         }
7     ans.push(u);
8 }
寻找欧拉道路或欧拉回路(无向图)

需要注意的是,我们此处标记的是边(或者删除边)。因为欧拉道路或欧拉回路是可以一口气走到结束的,所以上面的代码可以放心写个循环,且递归后不必跳出,因为当返回该点时,该点所连的其他边必然已经被走过了。因此答案里存的就是一条完整的路径。还有需要注意要先进行DFS遍历,最后存储答案,这叫做套圈法,可以处理环相连的情况。

 

无序字母对:https://www.luogu.org/problemnew/show/P1341


 

这道题的话,还是浪费了很多时间,一是因为欧拉回路以前没写过,而是因为这道题答案保存那里有点玄学问题,默默改成栈就过了(其实是因为无语的数组溢出,导致了奇怪的输出)。字符的处理也需要注意一下。如果直接读入到字符数组会WA的很惨。别问我是怎么知道的。。。

 1 #include <cstdio>
 2 #include <stack>
 3 
 4 using namespace std;
 5 
 6 const int maxa = 55;
 7 
 8 inline int toInt(char c) {
 9     if (c <= 'Z') return c - 'A' + 1;
10     else return c - 'a' + 27;
11 }
12 
13 inline char toChar(int i) {
14     if (i <= 26) return i - 1 + 'A';
15     else return i - 27 + 'a';
16 }
17 
18 int G[maxa][maxa], degree[maxa];
19 
20 stack<int> ans;
21 
22 void euler(int u) {
23     for (int v = 1; v <= 52; ++v)
24         if (G[u][v]) {
25             G[u][v] = G[v][u] = 0;
26             euler(v);
27         }
28     ans.push(u);
29 }
30 
31 int main() {
32     int n, a, b, s1 = 0, s2 = 0, cnt = 0;
33     scanf("%d", &n);
34     for (int i = 1; i <= n; ++i) {
35         char u = getchar();
36         while (u == '\n' || u == ' ' || u == '\r')
37             u = getchar();
38         char v = getchar();
39         a = toInt(u), b = toInt(v);
40         G[a][b] = G[b][a] = 1;
41         ++degree[a], ++degree[b];
42     }
43     for (int i = 1; i <= 52; ++i) {
44         if (degree[i] && !s1) s1 = i;
45         if (degree[i] % 2) {
46             ++cnt;
47             if (!s2) s2 = i;
48         }
49     }
50     if (cnt && cnt != 2) printf("No Solution");
51     else {
52         if (cnt) euler(s2);
53         else euler(s1);
54         if ((int)ans.size() != n + 1) printf("No Solution");
55         else while (!ans.empty()) {
56             printf("%c", toChar(ans.top()));
57             ans.pop();
58         }
59     }
60     return 0;
61 }
AC代码

 

转载于:https://www.cnblogs.com/Mr94Kevin/p/9532164.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值