按照题意建图,然后要求欧拉路径,对一个欧拉路径的判定
欧拉回路属于欧拉路径,而欧拉路径要求远比欧拉回路要求低。
无向图 当且仅当图中有两点度数为奇数,这两点为起点和终点,其他点度数皆为偶数且联通。
有向图 当且仅当其中一个顶点的入度少于出度1(起点),而另一点出度少于入度1(终点),其余节点出度=入度。图联通时。
至于为什么要倒着存,可以这样解释
input:
5
xx
xa
aa
ab
bx
output 50pts:
aabxax
output 100pts:
aabxxa
可以发现,50pts代码会贪心地挑较小结点访问,当访问到倒数第三个字母x时,会毫不犹豫地前往a,而不管这样做是否能遍历完,因此走到a无路可走了,又回到x遍历另外一个x,从而得到一个错误的答案
而100pts代码的好处在于,它是在遍历结束后将该结点逆序存入答案中,这就保证了无路可走的节点a一定是该序列的结尾(因为如果该结点还能继续访问,它就一定在那些能继续访问的点的前面),然后回到倒数第三个字母x寻找下一个x访问。此处不用担心x是否也是一个结尾(那样就无解了),因为通过递归前的判断,这张图中一定存在欧拉路,也就是只有一个终点
const int N=10007;
int m;
std::string s;
int g[N][N];
int ot[N];
char a[N];
int ans;
inline void print(){
drp(i,ans,1){
cout<<a[i];
}
cout<<'\n';
}
inline void dfs(int x){
rep(j,1,150){
if(g[x][j]){
--g[x][j];
--g[j][x];
dfs(j);
}
}
a[++ans]=x;
}
int main(){
std::ios::sync_with_stdio(false);
cin>>m;
rep(i,1,m){
cin>>s;
++g[s[0]][s[1]];
++g[s[1]][s[0]];
++ot[s[0]];
++ot[s[1]];
}
int cnt(0),a(0);
rep(i,1,150){
if(ot[i]&1){
++cnt;
if(!a) a=i;
}
}
if(!a) {
rep(i,1,150){
if(ot[i]) {
a=i;
break;
}
}
}
if(cnt&&cnt!=2){
puts("No Solution");
return 0;
}
dfs(a);
if(ans!=m+1){
puts("No Solution");
return 0;
}
print();
return 0;
}