Files
python/TangDou/AcWing/EulerPath/P1341.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

84 lines
2.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = N * N;
int g[N][N]; // 邻接矩阵
int start; // 起点
int d[N]; // 点的度
char ans[M]; // 拼接欧拉路径
int cnt; // 计数器,可重复利用
int n; // n个各不相同的无序字母对
// 并查集
int p[130]; // 'a'+26='z' 97+26=123
int find(int x) {
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
void dfs(int u) {
for (int i = 64; i <= 125; i++)
if (g[u][i]) {
g[u][i]--, g[i][u]--;
dfs(i);
}
ans[++cnt] = u;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("P1341.in", "r", stdin);
#endif
scanf("%d", &n); // n个各不相同的无序字母对
// 并查集初始化
for (int i = 64; i <= 125; i++) p[i] = i;
char s[3]; // 输入的字符串数组
for (int i = 1; i <= n; i++) {
scanf("%s", &s); // 读入n个无序字母对
int a = s[0], b = s[1];
g[a][b]++, g[b][a]++; // 记录点与点之间的连通关系,无向图记录,此方法可记录重边,当然,本题不需要处理重边
d[a]++, d[b]++; // 以字母的ASCII码作为节点编号,记录度
// 合并并查集,并查集的目的是看它们最终是不是连通的,如果点都不在一个集合中,就不可能出现欧拉路径
p[find(a)] = find(b);
}
for (int i = 64; i <= 125; i++) // 枚举'A'~'Z','a'~'z'
// d[i]表示此字母在上面的输入中出现过
// p[i]=i 表示检查完的家族数量
if (p[i] == i && d[i]) cnt++;
if (cnt != 1) {
puts("No Solution"); // 判断是否为欧拉通路
return 0;
}
cnt = 0; // 记录度是奇数的节点个数
for (int i = 64; i <= 125; i++)
if (d[i] % 2 == 1) { // 度为奇数,则必须是2个;当然,也可以全是偶数,没有奇数
cnt++;
if (start == 0) start = i; // 记录号最小的奇数度节点号,也就是出发点,因为本题要求输出字典序最小
}
// ① 奇数度节点个数是0,是可以的,此时比如是一个环
// ② 奇数度节点个数是2,是可以的,此时一个是起点,另一个是终点
if (cnt && cnt != 2) { // 如果两个都不是,那肯定就不存在欧拉路径
puts("No Solution");
return 0;
}
// 又见经典套路,如果每个点的度都是偶数,那么,出发点可以是任意一个度大于零的点,那就找出最小的那个吧
if (start == 0) {
start = 64;
while (!d[start]) start++;
}
// 通过dfs找出欧拉路径
cnt = 0;
dfs(start);
// 输出最终的欧拉路径字符串
for (int i = cnt; i; i--) printf("%c", ans[i]);
return 0;
}