参考的是这篇题解:洛谷P1127
原博客讲的很清楚了,主要就是用单词作为边来建图
+字典序排序
+深度遍历找欧拉路径
。
我用下面这个测试用例补充两个地方的解释
3
adc
caa
aaa
- 为什么要倒序加边
说白了就是因为是升序排序+深度遍历
倒序加边是这部分代码
for(int hd,tl,i=n;i>=1;i--){
hd=a[i][0]-'a'+1;
tl=a[i][a[i].size()-1]-'a'+1;
add(hd,tl,i);
}
排完序后,字符串数组的顺序是这样aaa,adc,caa,如果是正序加边,那么字母a对应的链表是这样的:adc
→
\rightarrow
→aaa,然后深度遍历的时候,就是先一直遍历到aaa这条边,然后加到ans数组里,这样就变成了最后输出的反而是字典序最小的单词
- 为什么在排完序后要设置st=a[1][0]-‘a’+1
虽然大部分情况下都是这样的:各个字母中,只有1个字母的度为1,1个字母的度为-1,其余字母的度都是0;但是在我提出的这个样例中,各个字母的度都是0,这样,通过下面这个循环来找出起点就不合适了
for(int i=1;i<=26;i++){
if(d[i]==1){
st=i;
break;
}
}
最后是我的代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=1005;
int lans;
typedef struct e{
int op;
int to;
int nxt;
}e;
e edge[maxn];
int d[30];//存储各个字母的度
int head[30];
bool use[maxn];
int tot;
void add(int x,int y,int op){
tot++;
edge[tot].op=op;
edge[tot].to=y;
edge[tot].nxt=head[x];
head[x]=tot;
d[x]++;
d[y]--;
}
string ans[maxn];
string a[maxn];
void dfs(int st){
for(int i=head[st];i;i=edge[i].nxt){
if(!use[edge[i].op]){
use[edge[i].op]=1;
dfs(edge[i].to);
lans++;
ans[lans]=a[edge[i].op];
}
}
}
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
for(int hd,tl,i=n;i>=1;i--){
hd=a[i][0]-'a'+1;
tl=a[i][a[i].size()-1]-'a'+1;
add(hd,tl,i);
}
int st;
st=a[1][0]-'a'+1;
for(int i=1;i<=26;i++){
if(d[i]==1){
st=i;
break;
}
}
dfs(st);
for(int i=1;i<=n;i++){
if(use[i]==0){
printf("***");
return 0;
}
}
for(int i=lans;i>1;i--){
cout<<ans[i]<<".";
}
cout<<ans[1];
}