题目描述

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

解析

毒瘤字符串读入

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 2010
#define MOD 2520
#define E 1e-12
using namespace std;
inline int read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
vector<int> g[N];
int m,n,top,minn=INF,deg[N];
char stack[N];
bool v[N][N];
inline void euler(int x)
{
for(int i=0;i<g[x].size();++i){
int y=g[x][i];
if(v[x][y]||v[y][x]) continue;
v[x][y]=v[y][x]=1;
euler(y);
}
stack[++top]=x;
}
int main()
{
m=read();
for(int i=1;i<=m;++i){
char s[3];
scanf("%s",s);
int x=s[0],y=s[1];
g[x].push_back(y),g[y].push_back(x);
deg[x]++,deg[y]++;
minn=min(minn,min((int)x,(int)y));
n=max(n,max((int)x,(int)y));
}
for(int i=minn;i<=n;++i)
sort(g[i].begin(),g[i].end());
int k=0,st=0;
for(int i=minn;i<=n;++i)
if(deg[i]&1){++k;if(!st)st=i;}//起点必须ASCII最小,且为奇点
if(!st)
for(int i=minn;i<=n;++i)
if(deg[i]){st=i;break;}//只有偶点
if(k!=2&&k){printf("No Solution");return 0;}//欧拉图存在性判断
euler(st);
if(top!=m+1){printf("No Solution");return 0;}//连通性判断
for(int i=top;i;--i) printf("%c",stack[i]);
return 0;
}

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. springboot统一返回json数据格式并配置系统异常拦截

    本文链接:https://blog.csdn.net/syystx/article/details/82870217通常进行前后端分离开发时我们需要定义统一的json数据交互格式并对系统未处理异常进行 ...

  2. canal部署启动的时候报错com.alibaba.druid.pool.DruidDataSource - testWhileIdle is true, validationQuery not set

    报错信息:com.alibaba.druid.pool.DruidDataSource - testWhileIdle is true, validationQuery not set 解决方法: 找 ...

  3. linux-sysbench

    sysbench是一个模块化的.跨平台.多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况.关于这个项目的详细介绍请看:http://sysbench.sourceforge.ne ...

  4. 16 JQuery---JavaScript框架

    1.JQuery概念一个JavaScript框架.简化JS开发JQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScr ...

  5. c++快速排序原理及优化

    快速排序 快速排序的时间复杂度为O(logn) 注意:快速排序主要是标志数的选取,如果所选的数恰好为最小或者最大,则是最糟糕的情况,即一轮下来数据没有发生变化! 如何选取中间的标志数成为了算法的关键. ...

  6. python基础 — 致初学者的天梯

    Python简介 Python是一种计算机程序设计语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新 功能的添加,越来越多被用于独立的.大型项目 ...

  7. leetcode两数相加

    题目描述:给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表 ...

  8. 【scratch3.0教程】1.3 了解scratch界面内容

    第3课 了解Scratch界面内容 1.认识Scratch界面 双击桌面快捷方式,启动Scratch程序.我们来认识一下Scratch界面吧! (1)指令区 Scratch程序一共有运动.外观.声音. ...

  9. sql 分组后重复数据取时间最新的一条记录

    1.取时间最新的记录 不分组有重复(多条CreateTime一样的都是最新记录) select * from test t where pid in ( select PId from Test t ...

  10. 【转载】C#中可使用string.Empty代表空字符

    在C#中,如果赋值一个字符串为空白字符串,我们一般会用“”的形式对字符串进行赋值操作,其实在C#的字符串类String类中,有个专门的常量string.Empty来代表空字符串,可直接在赋值的时候使用 ...