UESTC Training for Graph Theory——c、Catenyms

来源:互联网 发布:美白精华知乎 编辑:程序博客网 时间:2024/05/18 04:56

Catenyms

Time Limit: 1000 ms Memory Limit: 65536 kB Solved: 148 Tried: 1114

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 first 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

 

/*算法思想:  给几个单词,要求用完所有的单词一遍进行单词接龙,并且使接得的字符串的字典序最小  我们可以把每个单词抽象成一条边,边的起点是单词的第一个字符,边的终点是单词的最后一个字符  边的权值就是这个单词,这样,我们就构造出了一个图,问题就转化成了求一条这个图的欧拉路径,使  得欧拉路径上的单词拼接起来的字符串的字典序最小。  首先,我们要判断这个图是不是可以存在一个欧拉路径,使得我们能够不重复的访问完所有的边。  判断的方法就是统计图中所有节点的出度入度,要是出度入度不等,不存在,要是所有的点的出度均等于  入度,那么就找一个字典序最小的点作为起始点。  然后,我们需要判断图是不是只有一个联通块,只有在一个联通块的前提下,我们才能正确的找出欧拉路径  最后就是找欧拉路径了,需要对单词进行排序,排序的规则是按照单词的字典序从大到小排序,因为最终  我们输出答案的时候是逆着输出的,这样才能保证输出的路径满足字典序最小的规则。*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 2000using namespace std;struct data1{    char word[30];} s[N],ans[N];struct data2{    int st,en;    char val[30];    int next;} edge[N];int n,tot,st_id;int in[30],out[30],head[30],fa[30];bool vs[N],use[30];void make_set(){    for(int i=0;i<30;i++)        fa[i]=i;}int find_set(int x){    if(fa[x]!=x) fa[x]=find_set(fa[x]);    return fa[x];}void merge_set(int x,int y){    fa[y]=x;}void add_edge(int st,int en,char val[])  //加边{    in[en]++;    out[st]++;    use[st]=use[en]=true;    edge[tot].st=st;    edge[tot].en=en;    strcpy(edge[tot].val,val);    edge[tot].next=head[st];    head[st]=tot++;    int f1=find_set(st);    int f2=find_set(en);    if(f1!=f2) merge_set(f1,f2);}bool cmp(data1 a,data1 b)  //比较函数{   if(strcmp(a.word,b.word)>0) return true;   else return false;}bool judge()  //判断图中是否存在一条欧拉路径{    st_id=-1;    int sum1=0,sum2=0,set_num=0;    for(int i=0;i<26;i++)    if(use[i])    {        if(find_set(i)==i) set_num++;        if(set_num>1) return false;        if(in[i]-out[i]==1) sum2++;        else if(in[i]-out[i]==-1)        {            sum1++;            st_id=i;        }        else if(in[i]!=out[i]) return false;    }    if(set_num!=1) return false;  //如果不止一个联通块,不存在    if(!((sum1==1 && sum2==1) || (sum1==0 && sum2==0))) return false;  //通过点的入度出度判断是否存在    if(st_id==-1)  //如果是欧拉回路,我们要找一个最小的点作为起始点    {        for(int i=0;i<26;i++)            if(use[i] && out[i]>0)            {                st_id=i;                return true;            }    }    if(sum1==1 && sum2==1) return true;    return false;}void eular(int v,int id)  //dfs找欧拉回路{    for(int pos=head[v];pos!=-1;pos=edge[pos].next)        if(!vs[pos])        {            vs[pos]=true;            eular(edge[pos].en,pos);        }    if(id!=-1) strcpy(ans[++tot].word,edge[id].val);}int main(){    int t;    scanf("%d",&t);    for(int ca=1;ca<=t;ca++)    {        memset(in,0,sizeof(in));        memset(out,0,sizeof(out));        memset(head,-1,sizeof(head));        memset(edge,0,sizeof(edge));        memset(use,0,sizeof(use));        tot=1;        make_set();        scanf("%d",&n);        for(int i=1;i<=n;i++)            scanf("%s",s[i].word);        sort(s+1,s+n+1,cmp);        for(int i=1;i<=n;i++)        {            int st=s[i].word[0]-'a';            int en=s[i].word[strlen(s[i].word)-1]-'a';            add_edge(st,en,s[i].word);        }        if(judge())        {            tot=0;            memset(ans,0,sizeof(ans));            memset(vs,0,sizeof(vs));            eular(st_id,-1);            for(int i=tot;i>=1;i--)            {                printf("%s",ans[i].word);                if(i!=1) printf("."); else printf("\n");            }        }        else printf("***\n");    }    return 0;}