链接:https://www.luogu.org/problem/show?pid=1341
题目描述:
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
输入输出格式
输入格式:
第一行输入一个正整数n。
以下n行每行两个字母,表示这两个字母需要相邻。
输出格式:
输出满足要求的字符串。
如果没有满足要求的字符串,请输出“No Solution”。
如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案
输入输出样例
输入样例#1:
4 aZ tZ Xt aX
输出样例#1:
XaZtX
说明
【数据规模与约定】
不同的无序字母对个数有限,n的规模可以通过计算得到。
个人感觉这还是一道比较容易看出是是欧拉回路的题目呢。。
首先,是否存在欧拉路的条件:
建图:
将字母作为图的顶点,如果两字母间存在字母对就在相应的字母所对应的顶点连上一条五向边。
题目要求的是字典序最小的欧拉通路,怎么办呢?
首先来看看欧拉通路存在的条件:
1) 该连通图的所有节点的度均为偶数。
2)该连通图的奇点仅有两个。存在一条欧拉路从其中一个奇点出发,从另一个奇点结束....
如果不满足不满足欧拉通路的条件直接就是“”No Solution”
存在的话
那么利用dfs就可以求出.题目还有一个要求就是字典序最小,显然如果度数为奇数的点为两个,那么这两个点要么就是起点或终点,因为是无向图,所以不管是从起点出发还是从终点出发都是一样的,所以选择字典序小的一遍出发即可。。
代码:
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100;
int map[maxn][maxn], cnt[maxn], vis[maxn][maxn];
int n, maxm = 53;
stack <int> ans;
int zhuanhua1(char c)
{
if (c >= 'A' && c <= 'Z')
return (int)c - 'A';
return (int)c - 'a' + 26;
}
char zhuanhuan2(int x)
{
if (x >= 0 && x <= 25)
return (char)x + 'A';
return (char)(x - 26) + 'a';
}
void euler(int u)
{
for (int v = 0; v < maxm; v++)
if (map[u][v] && !vis[u][v])
{
vis[u][v] = vis[v][u] = 1;
euler(v);
ans.push(v);
}
}
int main()
{
scanf("%d%d", &n);
for (int i = 1; i <= n; i++)
{
char a, b;
cin >> a >> b;
int x = zhuanhua1(a), y = zhuanhua1(b);
map[x][y] = map[y][x] = 1;
cnt[x]++;
cnt[y]++;
}
int tot = 0, min1 = 1e8, min2 = 1e8;
for (int i = 0; i < maxm; i++)
{
if (cnt[i]%2==1)
{
tot++;
min1 = min(min1, i);
}
else if (cnt[i])
min2 = min(min2, i);
}
if (tot != 0 && tot != 2)
printf("No Solution\n");
else
{
int u;
if (tot == 0)
u = min2;
else
u = min1;
euler(u);
ans.push(u);
while (!ans.empty())
{
int temp = ans.top();
ans.pop();
char s = zhuanhuan2(temp);
cout << s;
}
printf("\n");
}
return 0;
}