题目描述

给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。

解析

毒瘤字符串读入

我就是不喜欢邻接矩阵,你咬我啊。

首先看到题目,由于存在n个不相同的无序字母对,且答案中要求题给字母对两字母相邻,容易分析出每个在字母对中出现的字母在答案中都至少要出现一次。即,如果数据有解,必然有出现字母种类\(<=\)n。

接下来看题目给出的另一条件,其要求我们构造一个含\(n+1\)个字母的含有所有给定字母对的字符串,并且每个字母对的两个字母需要相邻。那么就意味着在答案中一个字母对不能重复出现,否则字符串长度至少为\(n+2\)。

“相邻”是一种显而易见的抽象关系,我们在处理抽象关系时,往往要想到利用图论的特性限制这些抽象关系。

也就是说,我们把每个字母看成点,如果两个字母相邻,我们就在其间连一条无向边。那么连完之后,我们会发现我们要构造的答案其实就是一条路径,答案就是路径上的点。并且这条路径要在经过所有点的情况下不经过重复的边,因为经过了重复的边等同于一个字母对出现了两次,这是题目不允许的。

分析到这里,是不是很熟悉?

是的,这显然是要求一个欧拉路,那么我们直接求就行了。

这里给出欧拉路存在的条件:

  1. 无向图是连通图
  2. 图中恰好有两个节点度数为奇数,其余节点度数都为偶数。

感性证明:1就不用证了,只要稍微想想就能明白。。。对于2,其实奇数点就是欧拉路的起点和终点。显然,如果一个点度数为偶数,那么它可以被一条路径进入至多度数/2次,一条路径也可以从这个点出去至多度数/2次。如果一个点度为奇数,那么一条路径在进进出出它偶数次后,最后一次要不然是从这个点出去要不然是从某个点到这个点。

所以我们只要通过一些特判对不构成欧拉路的图输出无解就得了。

顺便也讲一下为什么要回溯时用栈来储存路径,而不是dfs时边往下搜边记录。

dfs时,系统栈如果遇到死路,不代表这个图就没有欧拉路了,因为dfs进程还在继续进行。意思就是说我们要记的路径和系统栈回溯时经过的路径是很可能不同的。

为什么呢?我们要输出的显然是在搜索树上一条符合要求的搜索路径,就是要搜到底,搜到把图中所有点都遍历到之后在再回溯时的路径,我们记下来才是对的。而系统栈回溯的时候,可能是因为走到了错误的分支,这个时候我们要是也记下来,毫无疑问是错的。

所以,我们等到系统栈因为搜索树最后一层都搜完而执行回溯时再记录路径。

参考代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<algorithm>
  6. #include<string>
  7. #include<cstdlib>
  8. #include<queue>
  9. #include<vector>
  10. #define INF 0x3f3f3f3f
  11. #define PI acos(-1.0)
  12. #define N 2010
  13. #define MOD 2520
  14. #define E 1e-12
  15. using namespace std;
  16. inline int read()
  17. {
  18. int f=1,x=0;char c=getchar();
  19. while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
  20. while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
  21. return x*f;
  22. }
  23. vector<int> g[N];
  24. int m,n,top,minn=INF,deg[N];
  25. char stack[N];
  26. bool v[N][N];
  27. inline void euler(int x)
  28. {
  29. for(int i=0;i<g[x].size();++i){
  30. int y=g[x][i];
  31. if(v[x][y]||v[y][x]) continue;
  32. v[x][y]=v[y][x]=1;
  33. euler(y);
  34. }
  35. stack[++top]=x;
  36. }
  37. int main()
  38. {
  39. m=read();
  40. for(int i=1;i<=m;++i){
  41. char s[3];
  42. scanf("%s",s);
  43. int x=s[0],y=s[1];
  44. g[x].push_back(y),g[y].push_back(x);
  45. deg[x]++,deg[y]++;
  46. minn=min(minn,min((int)x,(int)y));
  47. n=max(n,max((int)x,(int)y));
  48. }
  49. for(int i=minn;i<=n;++i)
  50. sort(g[i].begin(),g[i].end());
  51. int k=0,st=0;
  52. for(int i=minn;i<=n;++i)
  53. if(deg[i]&1){++k;if(!st)st=i;}//起点必须ASCII最小,且为奇点
  54. if(!st)
  55. for(int i=minn;i<=n;++i)
  56. if(deg[i]){st=i;break;}//只有偶点
  57. if(k!=2&&k){printf("No Solution");return 0;}//欧拉图存在性判断
  58. euler(st);
  59. if(top!=m+1){printf("No Solution");return 0;}//连通性判断
  60. for(int i=top;i;--i) printf("%c",stack[i]);
  61. return 0;
  62. }

P1341 无序字母对[欧拉路]的更多相关文章

  1. 洛谷 P1341 无序字母对(欧拉路)

    P1341 无序字母对 题目提供者yeszy 标签 福建省历届夏令营 难度 提高+/省选- 最新讨论 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造 ...

  2. 洛谷 P1341 无序字母对 解题报告

    P1341 无序字母对 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 ...

  3. 洛谷P1341 无序字母对(欧拉回路)

    P1341 无序字母对 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 ...

  4. P1341 无序字母对【欧拉路径】- Hierholzer模板

    P1341 无序字母对 提交 24.87k 通过 6.80k 时间限制 1.00s 内存限制 125.00MB 题目提供者yeszy 难度提高+/省选- 历史分数100 提交记录 查看题解 标签 福建 ...

  5. 洛谷P1341 无序字母对[无向图欧拉路]

    题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 输入格式: 第一行输入一 ...

  6. 洛谷 P1341 无序字母对 Label:欧拉路 一笔画

    题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 输入格式: 第一行输入一 ...

  7. 洛谷P1341 无序字母对【欧拉路】【dfs】

    题目:https://www.luogu.org/problemnew/show/P1341 题意:给定n对字母对,要求构造一个个数为n+1的字符串,使得每一个字母对都在里面出现过. 思路:这种题目都 ...

  8. P1341 无序字母对 欧拉回路

    题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 输入格式: 第一行输入一 ...

  9. P1341 无序字母对(欧拉回路)

    题目链接: https://www.luogu.org/problemnew/show/P1341 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一 ...

随机推荐

  1. 问题一:使用AndroidDriver而非原来的AppiumDriver的原因

    AppiumDriver升级到2.0.0版本引发的问题--Cannot instantiate the type AppiumDriver 1. 问题描述和起因在使用Appium1.7.0及其以下版本 ...

  2. [案例一] Spring中的事件驱动模型(机制)

    事件驱动模型是观察者模式的另一种形态,观察者相当于监听器,被观察者相当于事件源 事件源产生事件,监听器监听事件 以用户注册时候,要发送邮件和发送短信举例说明 定义一个事件 /** * spring会自 ...

  3. 函数的学习3——传递任意数量的实参&将函数存储在模块——参考Python编程从入门到实践

    传递任意数量的实参 形参前加一个 * ,Python会创建一个已形参为名的空元组,将所有收到的值都放到这个元组中: def make_pizza(*toppings): print("\nM ...

  4. SQL——LIKE操作符

    一.LIKE操作符的基本用法 LIKE操作符用于在WHERE子句中,搜索相似.类似的数据. LIKE操作符语法: SELECT 列名1,列名2... FROM 表名 WHERE 列名 LIKE xxx ...

  5. Python知识点图片

  6. 当base-package="controller.*"时,可见packageSearchPath为"classpath*:controller/*/**/*.class": 当base-package="controller.**"时,可见packageSearchPath为"classpath*:controller/**/**/*.class":

    今天在配置Spring的component-scan时,发现了一个有趣的问题.就是在指定base-package时,如果使用了星号通配符*,有时会出现类扫描不到的情况.下面研究一下这个问题. 先介绍一 ...

  7. Junit5中实现参数化测试

    从Junit5开始,对参数化测试支持进行了大幅度的改进和提升.下面我们就一起来详细看看Junit5参数化测试的方法. 部署和依赖 和Junit4相比,Junit5框架更多在向测试平台演进.其核心组成也 ...

  8. Android自动化测试之Monkey 转自:LupuX

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u011436666/article/details/53998332 在之前的文章Android自动 ...

  9. tkinter学习笔记_01

    知识点目录: 1. 文本框 Label var = tk.StringVar() # 文本框 bg 背景颜色 fonnt 字体设置 width 长 height 高 l = tk.Label(root ...

  10. 在windows中使用PuTTy上传下载文件和目录

    打开windows的cmd,使用cd命令切换到PuTTy安装目录 C:\Users\NUC>cd C:\Program Files\PuTTY 在cmd中使用pscp命令上传下载文件 windo ...