题目描述
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
输入输出格式
输入格式:第一行输入一个正整数n。
以下n行每行两个字母,表示这两个字母需要相邻。
输出格式:输出满足要求的字符串。
如果没有满足要求的字符串,请输出“No Solution”。
如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案
输入输出样例
输入样例#1:
4 aZ tZ Xt aX
输出样例#1:
XaZtX
说明
【数据规模与约定】
不同的无序字母对个数有限,n的规模可以通过计算得到。
分析:因为字母对的字母可以交换,所以我们可以想象成将n个字母对通过某种变换连成一起然后一次走到通.而n个字母对,n+1个字母组成字符串,说明每个字符都必须要在字符串中出现,也就是说选定一个起点,要在两个串之间的公共部分走到终点,而且n+1个字母不允许我们重复走,所以很容易联想到欧拉道路.那么我们建图,每一个字母对之间的字母连一条无向边,一个字母当作一个顶点,每连一条边,则两点的度数+1,如果度数为奇数的点只有两个或没有,那么就存在欧拉道路,那么利用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] & 1) { tot++; min1 = min(min1, i); } else if (cnt[i]) min2 = min(min2, i); } if (tot != 0 && tot != 2) printf("No Solution "); 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(" "); } return 0; }