A catenym is a pair of words separated by a period such that the last letter of the first word is the same as the last letter of the second. For example, the following are catenyms:
A compound catenym is a sequence of three or more words separated by periods such that each adjacent pair of words forms a catenym. For example,
aloha.aloha.arachnid.dog.gopher.rat.tiger
Given a dictionary of lower case words, you are to find a compound catenym that contains each of the words exactly once.
dog.gopher gopher.rat rat.tiger aloha.aloha arachnid.dog
A compound catenym is a sequence of three or more words separated by periods such that each adjacent pair of words forms a catenym. For example,
aloha.aloha.arachnid.dog.gopher.rat.tiger
Given a dictionary of lower case words, you are to find a compound catenym that contains each of the words exactly once.
Input
The first line of standard input contains t, the number of test cases. Each test case begins with 3 <= n <= 1000 - the number of words in the dictionary. n distinct dictionary words follow; each word is a string of between 1 and 20 lowercase letters on a line by itself.
Output
For each test case, output a line giving the lexicographically least compound catenym that contains each dictionary word exactly once. Output "***" if there is no solution.
Sample Input
2 6 aloha arachnid dog gopher rat tiger 3 oak maple elm
Sample Output
aloha.arachnid.dog.gopher.rat.tiger ***题意:给你一些单词,能否将这些单词首尾连接起来,即前一个单词的最后一个字母和后一个单词的第一个字母相同,若能输出该序列,若有多种则按字典序输出该序列。
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
int n,vis[1005],len[1005],k,in[27],out[27];
int ans[1005],cnt;
string s[1005];
struct node
{
int u,m;
};
vector<node> g[27];
void euler(int x)
{
for(int i=0; i<g[x].size(); i++)
{
int v=g[x][i].u;
if(!vis[g[x][i].m])
{
vis[g[x][i].m]=1;
euler(v);
cnt++;
ans[cnt]=g[x][i].m;//,记录路径编号,从而保存路径
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int start=100;
cin >> n;
cnt=k=0;
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i=1; i<=26; i++)
g[i].clear();
for(int i=1; i<=n; i++)
cin >> s[i];
sort(s+1,s+n+1);
start=s[1][0]-'a'+1;
// for(int i=1;i<=n;i++)
// {
// cout<<s[i]<<" ";
// }
for(int i=1; i<=n; i++)
len[i]=s[i].size();
for(int i=1; i<=n; i++)
{
node t;
t.u=s[i][len[i]-1]-'a'+1;
t.m=i;
g[ s[i][0]-'a'+1 ].push_back( t );
out[ s[i][0]-'a'+1 ]++;
in[s[i][len[i]-1]-'a'+1]++;
// start=min(start,s[i][0]-'a'+1);
// start=min(start,s[i][len[i]-1]-'a'+1);
}
//printf("%d\n",start);
int fin=0,fout=0,flag=0;
for(int i=1; i<=26; i++)//判断能不能构成欧拉回路
{
if(in[i]+1==out[i])
{
start=i;//一定要更新,因为虽然排序了,但是排序后的字符串有可能不能构成欧拉回路,比如:
//bdsfda asdjfdsuc csdfgfd dfdfewre efef,它排序之后为asdjfdsuc bdsfda csdfgfd dfdfewre efef
//显然按这个顺序是不能构成回路的,所以要重新更新start
fin++;//等于1 的话就说明单词的首尾字母是相同的,等于0就说明不相同,
//等于其它就说明首尾已经不能相连了,也就不能构成欧拉回路了
}//先把单词按字典序排序,然后判断是欧拉回路还是只是欧拉通路,如果是欧拉回路,直接从第0号单词开始搜,
//否则,找到出度比入度大1的那个单词开始搜。
else if(in[i]==out[i]+1)
{
fout++;//同上
}
else if(in[i]!=out[i]) flag=1;
}
//cout<<fin<<" "<<fout<<endl;
if(flag==1)
{
printf("***\n");
continue;
}
else if( (fin==1&&fout==1) || (fin==0&&fout==0) )
{
cnt=0;
euler(start);
if(cnt==n)
{
for(int i=cnt; i>=1; i--)
{
if(i==cnt)
cout << s[ ans[i] ];
else
cout << "." << s[ ans[i] ];
}
// for(int i=1;i<=n;i++)
// {
// if(i==1)
// cout<<s[i];
// else
// cout<<"."<<s[i];
// }
/*
5 ab ba ab ba ab,这样的样列就不能过,所以这样输出是错的
*/
printf("\n");
}
else
{
printf("***\n");
continue;
}
}
else
{
printf("***\n");
continue;
}
}
return 0;
}