很恶心的一条题,欧拉回路和欧拉通路问题,不过要记录路径。先用原始的方法判断能不能够构成欧拉通路或者欧拉回路。然后用深度检索的方法来搜索可行解。每次输入都在当前节点的所有路径中按字典序排序,这样就可以保证输出是词典序了。
/******************************************************************************* # Author : Neo Fung # Email : [email protected] # Last modified: 2011-10-21 19:38 # Filename: ZOJ1919 POJ2337 Catenyms.cpp # Description : ******************************************************************************/ // #include "stdafx.h" // #define DEBUG #include <fstream> #include <stdio.h> #include <iostream> #include <string.h> #include <string> #include <memory.h> #include <math.h> #include <algorithm> using namespace std; struct node { int to,id; //id代表这个节点在edge中的位置 bool used; //用于记录这个节点是否在深度优先搜索中用过 string str; node *next; }*adj[26],edge[2000],nTemp; int cou,n,start; int pre[26],ancient[2000],indegree[26],outdegree[26]; //pre用于并查集检索所有的路径是否连通,ancient用于记录每个单词出现顺序,indegree用于记录入度,outdegree用于记录出度 void init() { memset(adj,'\0',sizeof(adj)); memset(indegree,0,sizeof(indegree)); memset(outdegree,0,sizeof(outdegree)); for(int i=0;i<26;++i) pre[i]=-1; for(int i=0;i<n;++i) ancient[i]=-1; cou=0; } int find(const int &x) { if(pre[x]==-1) pre[x]=x; return x==pre[x]?x:find(pre[x]); } bool check() { int x=0; while(pre[x]==-1) ++x; start = x; //start用于记录起点,如果是欧拉回路的话,所有起点都可以,所以直接记录第一个了 int tep = pre[x]; for(;x<26;++x) { if(pre[x]!=-1) if(tep!=find(x)) return false; //不在同一棵树上,不行 } int sum=0; int temp[26]; memset(temp,0,sizeof(temp)); for(x=0;x<26;++x) if(outdegree[x]!=indegree[x]) temp[sum++]=x; if(sum==0) return true; //欧拉回路 if(sum ==2) //欧拉通路 if(outdegree[temp[0]]-indegree[temp[0]]==1 && indegree[temp[1]]-outdegree[temp[1]]==1) { start = temp[1]; //起点的入度比出度大1 return true; } else if(outdegree[temp[1]]-indegree[temp[1]]==1 && indegree[temp[0]]-outdegree[temp[0]]==1) { start = temp[0]; return true; } return false; } bool dfs(const int &s,const int &num) //深度优先搜索,s是当前节点,num是当前深度 { int to,id; bool used; if(num==n) //找到,返回 return true; node *head=adj[s]; while(head) { if(head->used) { head=head->next; continue; } to=head->to; id=head->id; ancient[num]=id; //记录这条边 head->used=true; if(dfs(to,num+1)) return true; head->used=false; head=head->next; } return false; } void input() { cin>>edge[cou].str; string &str= edge[cou].str; int to = *str.rbegin()-'a'; int from = *str.begin()-'a'; edge[cou].to= to; edge[cou].id=cou; edge[cou].used=false; ++indegree[from]; ++outdegree[to]; int a=find(from); int b=find(to); pre[a]=pre[b]=pre[from]=pre[to]=min(a,b); //并查集 //以下三个判断,用于给每个节点按照词典序排序 node *head=adj[from]; if(!head || head&&head->str > str) //string可以直接用<,>判断,返回结果是词典序结果。判断第一个节点是否存在,或者第一个节点存在且比本输入大 { edge[cou].next=head; adj[from] = &edge[cou++]; } else if(head && !head->next && head->str <str) //第一个节点存在,第二个节点不存在,且第一个节点比本输入小 { edge[cou].next = head->next; adj[from]->next = &edge[cou++]; } else { while(head->next && head->next->str < str) //找到一个位置,使得此位置的节点比本输入小,节点的下一个节点要么不存在,要么比本输入大 head=head->next; edge[cou].next = head->next; head->next = &edge[cou++]; } } int main(void) { #ifdef DEBUG freopen("data.txt","r",stdin); #endif int ncases; scanf("%d",&ncases); while(ncases--) { scanf("%d",&n); init(); for(int i=0;i<n;++i) input(); if(!check()) { cout<<"***"<<endl; continue; } dfs(start,0); cout<<edge[ancient[0]].str; for(int i=1;i<n;++i) { cout<<'.'<<edge[ancient[i]].str; } cout<<endl; } return 0; }