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:
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<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=10000;
int V,E;//点数 边数
struct edge
{
int t;//s->t=w
char w[30];
int next;
};
int p[maxn];//表头节点
edge G[maxn];//邻接表
void addedge(int u,int v,char* w,int l)//u->v=w, 邻接表节点 l
{
//cout<<u<<".."<<v<<".."<<w<<".."<<l<<endl;
strcpy(G[l].w,w);
G[l].t=v;
//G[l].next=p[u];
//p[u]=l;
//按照w从小到大排序
if(p[u]==-1)
{
G[l].next=p[u];
p[u]=l;
return ;
}
int index=-1,pre=-1;
for(int i=p[u];i!=-1;i=G[i].next)
{
//cout<<"ok"<<endl;
if(strcmp(G[i].w,w)>=0)
{
index=i;
break;
}
pre=i;
}
if(pre==-1)
{
G[l].next=p[u];
p[u]=l;
return ;
}
//cout<<pre<<"..."<<index<<endl;
G[l].next=G[pre].next;
G[pre].next=l;
}
//并查集 判断弱连通
int fath[maxn];
int find(int x)
{
return fath[x]==x?x:fath[x]=find(fath[x]);
}
void uion(int x,int y)
{
x=find(x);y=find(y);
if(x==y) return ;
fath[x]=y;
}
//欧拉路
int in[maxn],out[maxn];//入度 出度
int flag;//判断是否存在欧拉路
int s0,t0;//欧拉路出发点 终结点
int ans[maxn];//保存欧拉路
int cur;//欧拉路长度
bool used[maxn];//判断边是否用过
///输出欧拉路
void dfs(int x,int cas)//顶点 边
{
for(int i=p[x];i!=-1;i=G[i].next)
{
if(!used[i])
{
used[i]=1;
dfs(G[i].t,i);
}
}
if(cas!=-1) ans[cur++]=cas;
}
void print()//逆序输出
{
for(int i=cur-1;i>0;i--)
{
printf("%s.",G[ans[i]].w);
}printf("%s/n",G[ans[0]].w);
}
int main()
{
int ci;scanf("%d",&ci);
while(ci--)
{
scanf("%d",&E);V=26;
memset(p,-1,sizeof(p));
for(int i=1;i<=V;i++) fath[i]=i;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(used,0,sizeof(used));
char ch[25];int vis[27]={0};
for(int i=0;i<E;i++)
{
scanf("%s",ch);
int u=ch[0]-'a'+1,v=ch[strlen(ch)-1]-'a'+1;
uion(u,v);vis[u]=vis[v]=1;
in[v]++,out[u]++;
addedge(u,v,ch,i);//w按照从小到大排序
}
flag=1;
//判断弱连通
int f1=-1;
for(int i=1;i<=V;i++)
{
if(vis[i])
{
if(f1==-1) f1=find(i);
else
{
if(f1!=find(i))
{
flag=0;
break;
}
}
}
}
if(!flag) {printf("***/n");continue;}
int ns0=0,nt0=0;//个数 >1时不存在欧拉路
for(int i=1;i<=V;i++)
{
if(!vis[i]) continue;
if(in[i]<out[i])
{
if(out[i]-in[i]==1) ns0++,s0=i;
else flag=0;
}
else if(in[i]>out[i])
{
if(in[i]-out[i]==1) nt0++,t0=i;
else flag=0;
}
}
if(!(ns0<=1&&nt0<=1&&ns0==nt0)) flag=0;
if(!flag) {printf("***/n");continue;}
if(ns0==1)
{
cur=0;
dfs(s0,-1);
}
else
{
cur=0;
for(int i=1;i<=V;i++)
{
if(vis[i])
{
dfs(i,-1);
break;
}
}
}
print();
}
return 0;
}