Catenyms
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 9905 | Accepted: 2588 |
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:
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 ***
这道题跟成语接龙很像,即第一个单词的最后一个字母和第二个单词的首字母是相同的,给你n个单词,问能否接起来,能并且不止一种的话,输出字典序最小的一个,没有输出"***"。。
首先,我们将这些单词转化为有向图,即一个单词为一条边,首字母为起点,最后一个字母为终点。
然后,对于一个有向图,是否存在欧拉路径,判定条件有两个,1、图是连通的(并查集) 2、每个点的入度=出度 或 只有两个点 入-出=1(终点) 出-入=1(起点)。。
最后,将按字典序排序后的每条边,从起点开始DFS,将所有的边遍历一遍,并记录下路径,即为最后结果。。
WA了一天,最后发现没有考虑所有点入度都等于出度的情况,sad~~
#include <iostream> #include <cstdio> #include <cstring> #include <stdlib.h> #include <algorithm> #define M 30 #define N 1010 using namespace std; struct node { int x,y; //每条边的起终点 char s[M]; //记录每个单词 } q[N]; int n; //单词数,即边数 int bin[N]; int in[M],out[M]; //入度,出度 int v[M],b[N]; //节点是否存在标志,边是否访问标志 int xx; //起点 char ans[N][M]; //记录路径 int k; int cmp(void const *a,void const *b) { return strcmp((*(node*)a).s , (*(node*)b).s); } int findx(int x) { int r=x; while(bin[r]!=r) r=bin[r]; return r; } void merge(int x,int y) { int fx,fy; fx=findx(x); fy=findx(y); if(fx!=fy) bin[fx]=fy; } bool connect() { for(int i=0; i<26; i++) //并查集判定是否连通 { if(v[i]) { for(int j=i+1; j<26; j++) if(v[j] && findx(i)!=findx(j)) return true; break; } } int s=0; for(int i=0; i<26; i++) //判定是否有度不相等的情况 { if(v[i]) { if(in[i]!=out[i]) { if(in[i]-out[i]==1||out[i]-in[i]==1) { s++; if(s>2) return true; if(out[i]-in[i]==1) xx=i; //找到起点 } else return true; } } } if(xx==-1) //没有找到起点,说明所有点入度=出度,所有最小的节点当起点 { for(int i=0; i<26; i++) //就是缺了这个判断WA了一天。。。。。 { if(v[i]) { xx=i; break; } } } return false; } void dfs(int r) { for(int i=0; i<n; i++) { if(!b[i] && q[i].x==r) //找到该边且未访问过 { b[i]=1; //标记访问 dfs(q[i].y); //从该边的终点继续往下寻找 strcpy(ans[k++],q[i].s); //记录路径,用来输出 } } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0; i<26; i++) bin[i]=i; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(v,0,sizeof(v)); for(int i=0; i<n; i++) { scanf("%s",q[i].s); int len=strlen(q[i].s); q[i].x=q[i].s[0]-'a'; q[i].y=q[i].s[len-1]-'a'; out[q[i].x]++; //出度+1 in[q[i].y]++; //入度+1 v[q[i].x]=1; //标记该节点存在 v[q[i].y]=1; merge(q[i].x,q[i].y); } xx=-1; //初始化起点 qsort(q,n,sizeof(q[0]),cmp); //按字典序排序 if(connect()) //图是否连通 && 是否存在欧拉路径 { printf("***\n"); continue; } k=0; memset(b,0,sizeof(b)); //边访问标记 dfs(xx); //从起点开始遍历每条边 for(int i=k-1; i>=1; i--) printf("%s.",ans[i]); printf("%s\n",ans[0]); } return 0; }