Catenyms
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 11660 Accepted: 3037
Description
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
***
Source
Waterloo local 2003.01.25
http://blog.csdn.net/LuRiCheng/article/details/52415262的升级版
如果把字母当做点
把单词当做边 例如:dog=>从d到g的有向边
建图后 不难发现 这其实就是欧拉回路的变种 一笔画问题
至于输出回路 dfs即可
PS:POJ不支持string.back() 真蛋疼
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<time.h>
#include<math.h>
#include<list>
#include<cstring>
#include<fstream>
//#include<memory.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define INF 1000000007
#define pll pair<ll,ll>
#define pid pair<int,double>
const int N=1000+5;//最大边数
vector<string>vec;//边
int inDegree[26];//入度
int outDegree[26];//出度
int par[26];//并查集
vector<int>G[26];//邻接表 G[i]保存从i出发的边的下标 下标按边的字典序排序
bool used[N];//dfs标记
deque<string>ans;//答案
inline int find(int i){
return par[i]=(par[i]==i?i:find(par[i]));
}
inline void unite(int i,int j){
par[find(i)]=find(j);
}
void builtG(){
for(int i=0;i<26;++i)
G[i].clear();
//对边进行排序 dfs时按顺序搜索 找到的第一个合法回路就是字典序最小的回路
sort(vec.begin(),vec.end());
for(int i=0;i<vec.size();++i){
int st=vec[i][0]-'a';
G[st].push_back(i);
}
}
void dfs(int in){
for(int i=0;i<G[in].size();++i){
int strIndex=G[in][i];
if(!used[strIndex]){
used[strIndex]=true;
int to=vec[strIndex][vec[strIndex].size()-1]-'a';
dfs(to);
ans.push_front(vec[strIndex]);
}
}
}
int main()
{
//freopen("/home/lu/文档/r.txt","r",stdin);
//freopen("/home/lu/文档/w.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
vec.clear();
vec.resize(n);
//ini
fill(inDegree,inDegree+26,0);
fill(outDegree,outDegree+26,0);
for(int i=0;i<26;++i)
par[i]=i;
for(int i=0;i<n;++i){
cin>>vec[i];
int st=vec[i][0]-'a';
int end=vec[i][vec[i].size()-1]-'a';
++outDegree[st];
++inDegree[end];
unite(st,end);
}
//check is-unicom
int numOfSet=0;//检测所有边是否在一个联通集合中
for(int i=0;i<26;++i)
numOfSet+=(inDegree[i]+outDegree[i]>0&&par[i]==i);
if(numOfSet>1){
printf("***\n");
continue;
}
//check inDegree and outDegree
int in=-1,out=-1;//检测入度出度是否符合一笔画
bool noResult=false;
for(int i=0;i<26;++i){
int dt=inDegree[i]-outDegree[i];
if(dt==1){
if(out>=0){
noResult=true;
break;
}
out=i;
}
else
if(dt==-1){
if(in>=0){
noResult=true;
break;
}
in=i;
}
else
if(dt!=0){
noResult=true;
break;
}
}
if(noResult){
printf("***\n");
continue;
}
//dfs找出回路
fill(used,used+n,false);
builtG();
ans.clear();
if(in>=0)
dfs(in);
else
for(int i=0;i<26;++i)
if(inDegree[i]>0){
dfs(i);
break;
}
cout<<ans.front();
for(int i=1;i<ans.size();++i)
cout<<"."<<ans[i];
cout<<endl;
}
return 0;
}