Catenyms
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 9617 | Accepted: 2524 |
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 ***
解决方案:首先建立一个图的模型:用单词的首尾字母做节点,用单词做边。这些单词能连成一串,必须:1)能形成欧拉路或欧拉回路;2)要能构成一个连通图。先是判断是欧拉回路/欧拉路:记录每个顶点的出度与入度,若有一个点出度大入度1,一个点入度大出度1,其余出度等于入度,则为欧拉路;若每个店的出度与入度都相等,则为欧拉回路。然后判断是否为联通的,可用并查集来判断,这个就不用说了。然后是怎么建图的问题,这个最好用头插法建图,记录每个顶点所连得边及终点。再则就是输出要字典序的问题,可以这样子,先对单词进行排序,然后按照排好顺序的单词建图,是要从小到大,还是从大到小排呢。若是从小到大,由于是头插法建图,那么每次遍历边的时候,这个按字典序从大到小来遍历的,所以,我们应该从大到小排序。还有就是起点的问题:若是欧拉路,则出度比入度大1的那个点做起点,若是欧拉回路,字典序最小的点做起点。
code:#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<stack> #define MMAX 1003 using namespace std; string word[MMAX]; int fa[27],in[27],out[27]; int Map[27][27]; bool vise[MMAX]; bool cmp(string a,string b) { return a>b; } stack<string>S; int N,k; int head[27]; struct node { int from,to; string word; int next; } E[MMAX]; void add(int from,int to,string word) { E[k].from=from; E[k].to=to; E[k].word=word; E[k].next=head[from]; head[from]=k++; } bool vis[27]; int faset(int x) { return x!=fa[x]?fa[x]=faset(fa[x]):x; } int C(char c) { return int(c-'a'); } void dfs(int v) { for(int i=head[v]; i!=-1; i=E[i].next) { if(!vise[i]) { vise[i]=true; dfs(E[i].to); S.push(E[i].word); } } } int main() { int t; scanf("%d",&t); while(t--) { memset(head,-1,sizeof(head)); memset(vis,false,sizeof(vis)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(Map,0,sizeof(Map)); memset(vise,false,sizeof(vise)); while(!S.empty())S.pop(); for(int i=0; i<26; i++) { fa[i]=i; } scanf("%d",&N); for(int i=0; i<N; i++) { cin>>word[i]; } sort(word,word+N,cmp); k=0; for(int i=0; i<N; i++) { int len=word[i].length(); int st=C(word[i][0]),en=C(word[i][len-1]); add(st,en,word[i]); int x=faset(st),y=faset(en); vis[st]=true,vis[en]=true; if(x!=y) { fa[x]=y; } in[en]++,out[st]++; } bool flag=true; int pre=faset(C(word[0][0])); for(int i=0; i<26; i++) { if(vis[i]) { if(pre!=faset(i)) { flag=false; break; } } } int st,cst=0,cen=0,cnt=0; st=C(word[N-1][0]); for(int i=0; i<26; i++) { if(in[i]!=out[i]) { if(abs(in[i]-out[i])>1) { flag=false; break; } if(in[i]+1==out[i]) cst++,st=i; if(out[i]+1==in[i]) cen++; cnt++; } } if((cst==1&&cen==1)||!cnt) ; else flag=false; if(flag) { dfs(st); while(!S.empty()) { string temp=S.top(); S.pop(); cout<<temp<<"."; if(S.size()==1) break; } cout<<S.top()<<endl; S.pop(); } else { printf("***\n"); } } return 0; }
Catenyms+欧拉回路/欧拉路+并查集+POJ