POJ 2337 Catenyms (欧拉回路)
Catenyms
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 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 |
题目大意:输入n个单词,每个单词都形成一条从该单词首字母到尾字母的边,单词尾字母要与下一个单词首字母相同,若可以组成这样的路,即可以组成这样一条连着的单词串,输出路径(单词串),若有多条,则要按字典顺序输出,找不到路则输出***。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,cnt,head[30]; int tot,odd,src,des,mark[30],indeg[30],outdeg[30],deg[30],father[30]; char res[1010][30]; struct Edge{ bool vis; char wrd[30]; int to,nxt; }edge[1010]; int cmp(Edge a,Edge b){ return strcmp(a.wrd,b.wrd)>0; } void init(){ tot=odd=0; memset(mark,0,sizeof(mark)); memset(indeg,0,sizeof(indeg)); memset(outdeg,0,sizeof(outdeg)); memset(head,-1,sizeof(head)); for(int i=0;i<1010;i++) edge[i].vis=0; for(int i=0;i<26;i++) father[i]=i; } int findSet(int x){ if(x!=father[x]){ father[x]=findSet(father[x]); } return father[x]; } int judge(){ //判断是否满足欧拉。0不满足,1欧拉回路,2欧拉路 int i,k; for(i=0;i<26;i++){ //判断有向图欧拉 if(!mark[i]) continue; deg[i]=indeg[i]-outdeg[i]; if(abs(deg[i])>1) return 0; if(deg[i]>0) src=i; //起点 if(deg[i]<0) des=i; //终点 if(deg[i]%2) odd++; if(odd>2) return 0; } for(i=0;i<26;i++) if(mark[i]) break; k=findSet(i); for(i=k+1;i<26;i++){ //判断连通性 if(!mark[i]) continue; if(k!=findSet(i)) return 0; } if(odd==0){ //有欧拉回路 for(i=0;i<26;i++) if(mark[i]) break; src=i; return 1; } return 2; } void DFS(int u,int id){ //深搜寻找欧拉路径, for(int i=head[u];i!=-1;i=edge[i].nxt) if(!edge[i].vis){ edge[i].vis=1; DFS(edge[i].to,i); } if(id!=-1) strcpy(res[tot++],edge[id].wrd); //最先进去的肯定是终点 } int main(){ //freopen("input.txt","r",stdin); int t; scanf("%d",&t); while(t--){ init(); scanf("%d",&n); for(int i=0;i<n;i++) scanf("%s",edge[i].wrd); sort(edge,edge+n,cmp); //题目要求是字典顺序,但是我是用前插链表,这时的顺序恰好会相反 ,所以排序时从大到小,这样刚刚会是字典顺序 for(int i=0;i<n;i++){ int len=strlen(edge[i].wrd); int x=edge[i].wrd[0]-'a'; int y=edge[i].wrd[len-1]-'a'; indeg[x]++; outdeg[y]++; mark[x]=true; mark[y]=true; edge[i].to=y; edge[i].nxt=head[x]; head[x]=i; //建边 int fx=findSet(x); int fy=findSet(y); if(fx!=fy) father[fx]=fy; } if(judge()==0){ printf("***\n"); continue; } DFS(src,-1); for(int i=tot-1;i>0;i--) printf("%s.",res[i]); printf("%s\n",res[0]); } return 0; }