Description
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。
Input
第一行输入一个正整数n.以下n行每行两个字母,表示这两个字母需要相邻。
Output
输出满足要求的字符串。如果没有满足要求的字符串,请输出“No Solution”。如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案。
Hint
不同的无序字母对个数有限,n的规模可以通过计算得到
Solution
这道题需要计算一条欧拉路径,无序所以是无向图,由于数据规模较大用邻接矩阵来存会爆RE所以这个无向图只能用用vector来存,存的是char字符和每条边的id。字典序需要最小所以输入所有路径后需要将g从小到大进行排序。然后vector一个ep序列记录欧拉路径树的后序遍历结果,这里有一个需要注意的地方详见注意事项。
判断无解就需要记录每个结点的度,如果不等于0和2(即不是欧拉回路或者欧拉路),那么就直接输出无解后retrun 0。如果满足条件,因为字典序要最小所以要找到第一个最小的奇点,并且将start更新成它。如果没有奇点那么在init中已经将start更新成字典序最小的结点作为路径的开端了。然后就是欧拉路径dfs。
注意事项:
1.因为vector是从0位置开始输入并且size()返回的是+1的大小所以循环的时候从0开始且结束循环不用取等。
2.输入的时候不要用getchar()因为getchar会把回车输进去所以用一个str数组存字符串然后使起点和终点等于str[0]和str[1]。
3.存的是无向图所以一条边id要一样。
4.排序的时候循环是从字符'A'到'z',不是从1到n。
5.输出的时候将后序遍历结果倒着输出,同样需要注意size()不取等,结束在0位置。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 100005
using namespace std;
struct edge{
char v;
int id;
};
char x,y,start;
int n,cnt;
char str[5];
int num[maxn];
bool vis[maxn];
vector<edge>g[maxn];
vector<char>ep;
bool cmp(edge x,edge y){
return x.v<y.v;
}
void init(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",str);
x=str[0];
y=str[1];
if(i==1)start=x;
if(start>x)start=x;
if(start>y)start=y;
g[x].push_back((edge){y,i});
g[y].push_back((edge){x,i});
num[x]++;
num[y]++;
}
for(int i='A';i<='z';i++)
sort(g[i].begin(),g[i].end(),cmp);
}
void find_circle(char x){
for(int k=0;k<g[x].size();k++){
char j=g[x][k].v;
int id=g[x][k].id;
if(vis[id])continue;
else vis[id]=true;
find_circle(j);
}
ep.push_back(x);
}
int main(){
init();
for(char i='A';i<='z';i++){
if(num[i]%2==1){
cnt++;
}
}
if(cnt!=0&&cnt!=2){
printf("No Solution\n");
return 0;
}
if(cnt==2){
for(int i='A';i<='z';i++){
if(num[i]&1){
start=i;
break;
}
}
}
find_circle(start);
for(int p=ep.size()-1;p>=0;p--){
printf("%c",ep[p]);
}
putchar('\n');
return 0;
}