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
*** 思路:
可以将每个单词看作是两点一边,就变成判断欧拉路径(回路)了,从连通性和出度入度两方面判断,然后打印欧拉路径即可,代码如下(注释
int in[], out[], ans[], start, fa[], n, k;

struct edge {
int u, v, vis;
string s;
bool operator<(const edge &a) const {
return s<a.s;
}
} Edge[]; void init() {
memset(in, , sizeof(in)), memset(out, , sizeof(out));
memset(ans, , sizeof(ans));
k = ;
for(int i = ; i <= ; ++i)
fa[i] = i;
} // Find-Union
int Find(int u) {
if(fa[u] != u)
return fa[u] = Find(fa[u]);
return fa[u];
} void Union(int x, int y) {
x = Find(x), y = Find(y);
if(x != y) fa[x] = y;
} // judge whether connected bool Connect() {
int now = Find(start);
for(int i = ; i <= ; ++i)
if(in[i] || out[i])
if(Find(i) != now)
return false;
return true;
} // judge the in and out and set the start bool check() {
int t1 = , t2 = , i;
for(i = ; i <= ; ++i) {
if(in[i] == out[i]) continue;
else if(in[i] == out[i] + )
t1++;
else if(in[i] == out[i] - ) {
t2++;
start = i;
}
else
break;
}
if(i == && t1 == t2 && (t1 == || t1 == )) {
return true;
}
return false;
} //print the euler path
void dfs(int v) {
for(int i = ; i <= n; ++i) {
if(Edge[i].vis == && Edge[i].u == v) {
Edge[i].vis = ;
dfs(Edge[i].v);
ans[k++] = i;
}
}
} int main() {
ios::sync_with_stdio(false);
int T;
cin >> T;
while(T--) {
cin >> n;
init();
for(int i = ; i <= n; ++i) {
int u, v;
cin >> Edge[i].s;
u = Edge[i].s[] - 'a' + ;
v = Edge[i].s[Edge[i].s.size()-] - 'a' + ;
in[v]++, out[u]++;
Edge[i].u = u, Edge[i].v = v, Edge[i].vis = ;
Union(u, v);
}
sort(Edge+, Edge++n);
start = Edge[].u;
if(check() && Connect()) {
dfs(start);
for(int i = n-; i >= ; --i)
cout << Edge[ans[i]].s << ".";
cout << Edge[ans[]].s << "\n";
} else {
cout <<"***\n";
}
}
return ;
}
 

最新文章

  1. fir.im Weekly - iOS / Android 动态化更新方案盘点
  2. MongoDB 由于目标计算机积极拒绝,无法连接 2014-07-25T11:00:48.634+0800 warning: Failed to connect to 127.0.0.1:27017, reason: errno:10061
  3. First Blog
  4. OpenCV2:图像的几何变换,平移、镜像、缩放、旋转(2)
  5. 再谈Newtonsoft.Json高级用法
  6. Javascript Window的属性
  7. Nodejs系列-01-开篇
  8. Android三种消息提示
  9. 织梦dedecms调用子栏目的方法
  10. poj2352消防站
  11. UCOS-消息队列(学习笔记)
  12. 设计模式之桥接模式(Bridge)
  13. C# API: 生成和读取Excel文件
  14. 事件兼容IE
  15. Java程序发展之路
  16. ExecuteScalar 要求已打开且可用的 Connection。连接的当前状态为已关闭。
  17. php笔试题1
  18. ActionScript简单实现Socket Tcp应用协议分析器
  19. Linux多线程服务端编程:使用muduo C++网络库
  20. Python之路:常用算法与设计模式

热门文章

  1. 分布式应用监控:SkyWalking 快速接入实践
  2. Django--redis 保存session
  3. (任意进制转换)将 r 进制数转成 k 进制数
  4. 基于Modelsim的视频流仿真
  5. Codeforces Round #594 (Div. 2) - C. Ivan the Fool and the Probability Theory(思维)
  6. GsonUtils.getGson().fromJson() 转泛型集合用法
  7. 「APIO2012」派遣
  8. CSP-S 2019 初赛游记
  9. Python 基础之函数的嵌套与nonlocal修改局部变量及闭包函数
  10. Scrapy 中的模拟登陆