题目:https://www.luogu.org/problemnew/show/P1341
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
欧拉路相关知识:https://blog.csdn.net/chenxiaoran666/article/details/82533147
题解:
这里就可以发现实际上就是在找欧拉路,
首先每个字符就是代表的图中的某一个点,输入的字符串,就代表两点之间有连通,
构造字符串就是在找输出一笔画回路,明白这个代码就很简单了。
#include <cstdio>
#include <iostream>
using namespace std;
// 'z'=122 字母最大不超过122 //很奇怪,我填150+5,后面第#8 9 10,都RE了 TAT
const int maxn = 200 + 5;
int n, ans;
int dis[maxn][maxn], depth[maxn]; // dis代表两点连接的数量,depth代表度数
char a[maxn]; //存路径
void dfs(int i) { //深搜找欧拉路,i表示当前找的这个点
for (int j = 1; j < maxn; j++) {
if (dis[i][j]) { //如果两点之间有连通
dis[i][j]--; //毁图大法
dis[j][i]--;
dfs(j);
}
}
a[++ans] = i; //记录路径
return;
}
int main() {
// freopen("data.txt","r",stdin);
string s;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> s;
dis[s[0]]
[s[1]]++; //记录路径,数组第一维表示当前的点,与第二维的点有连接
dis[s[1]][s[0]]++;
depth[s[0]]++; //记录度数
depth[s[1]]++;
}
int cnt = 0, h = 0; //开始找点,//h,最开始找到的设置为起点,即为最小ASCLL码开始
for (int i = 1; i < maxn; i++)
if (depth[i] & 1) { //找度数为奇数的点,第一个置为起点
cnt++;
if (!h)
h = i;
}
if (cnt && cnt != 2) { //没有奇点或者奇点数量不为2,就不形成一个欧拉路
cout << "No Solution";
return 0;
}
if (!h) //找不到奇点,就是另外找点(度数不为0的任意一点)
for (int i = 1; i < maxn; i++)
if (depth[i]) {
h = i;
break;
}
dfs(h);
if (ans <
n + 1) { //搜完以后判断一下,因为n组连边,必有n+1个点,前提是不重复
cout << "No Solution";
return 0;
}
for (int i = ans; i >= 1; i--) //倒叙输出,因为存点是深搜之后存的点
cout << a[i];
cout << endl;
return 0;
}