poj 2337 Catenyms(欧拉路径+并查集)

Catenyms
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 8078 Accepted: 2127

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

思路:

欧拉回路:图G,若存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路,如果存在一条回路经过G每条边有且仅有一次,

称这条回路为欧拉回路。具有欧拉回路的图成为欧拉图。

判断欧拉路是否存在的方法

有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度。

无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的。

判断欧拉回路是否存在的方法

有向图:图连通,所有的顶点出度=入度。

无向图:图连通,所有顶点都是偶数度。

程序实现一般是如下过程:

1.利用并查集判断图是否连通,即判断p[i] < 0的个数,如果大于1,说明不连通。

2.根据出度入度个数,判断是否满足要求。

3.利用dfs输出路径。

代码:

 

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<stdio.h>
  4 #include<string.h>
  5 #include<math.h>
  6 #include<queue>
  7 #include<stack>
  8 using namespace std;
  9 
 10 
 11 struct Nod
 12 {
 13     int next;
 14     int to;
 15     char str[30];
 16 }node[1010];
 17 
 18 int parent[30];
 19 //下面数组分别为出度,入度,存在标记,
 20 int in[30],out[30],existmark[30],used[1010],adj[30];
 21 
 22 stack<int> st;  //保存最后的结果,倒序输出
 23 
 24 //并查集1
 25 int findp(int u)
 26 {
 27     while(u!=parent[u])
 28     {
 29         u=parent[u];
 30     }
 31     return u;
 32 }
 33 
 34 //并查集2
 35 void unit(int u,int v)
 36 {
 37     int r1=findp(u);
 38     int r2=findp(v);
 39     if(r1==r2)
 40         return ;
 41     parent[r1]=r2;
 42 }
 43 
 44 //排序,字典序倒序
 45 bool cmp(Nod p1, Nod p2)
 46 {
 47     return strcmp(p1.str, p2.str) > 0;
 48 }
 49 
 50 //初始化
 51 void init()
 52 {
 53     int i;
 54     for(i=0;i<26;i++)
 55         parent[i]=i;
 56     memset(in,0,sizeof(in));
 57     memset(out,0,sizeof(out));
 58     memset(existmark,0,sizeof(existmark));
 59     memset(used,0,sizeof(used));
 60     memset(adj,-1,sizeof(adj));
 61 }
 62 //欧拉路
 63 void Eular(int start,int pos)
 64 {
 65     int i;
 66     for(i=adj[start];i!=-1;i=node[i].next)
 67     {
 68         if(!used[i])
 69         {
 70             used[i]=1;
 71             Eular(node[i].to,i);
 72         }
 73     }
 74     if(0 <= pos)
 75         st.push(pos);
 76 }
 77 
 78 int main()
 79 {
 80     int t;
 81     scanf("%d",&t);
 82     while(t--)
 83     {
 84         int n;
 85         scanf("%d",&n);
 86         init();
 87         int i,v,u;
 88         for(i=0;i<n;i++)
 89         {
 90             scanf("%s",node[i].str);
 91         }
 92         sort(node, node + n, cmp);
 93         for(i=0;i<n;i++)
 94         {
 95             u=node[i].str[0]-'a';
 96             v=node[i].str[strlen(node[i].str)-1]-'a';
 97             out[u]++;
 98             in[v]++;
 99             existmark[u]=1;
100             existmark[v]=1;
101             unit(u,v);
102             node[i].to=v;
103             node[i].next=adj[u];
104             adj[u]=i;
105            // cout<<i<<" "<<u<<" "<<node[i].next<<endl;
106         }
107 
108         int flag=0;
109         for(i=0;i<26;i++)
110         {
111             if(existmark[i]&&parent[i]==i)
112                 flag++;
113         }
114         if(flag>1)
115         {
116             printf("***\n");
117             continue;
118         }
119 
120         int a=0,b=0,start=-1;
121         for(i=0;i<26;i++)
122         {
123             if(in[i]!=out[i]&&existmark[i])
124             {
125                 if(1==in[i]-out[i])
126                 {
127                     a++;
128                 }else if(1==out[i]-in[i])
129                 {
130                     b++;
131                     start=i;
132                 }else
133                 {
134                     break;
135                 }
136             }
137         }
138         if(i<26)
139         {
140             printf("***\n");
141             continue;
142         }else
143         {
144             if(!((0 == a + b) || (1 == a && 1 == b)))
145             {
146                 printf("***\n");
147                 continue;
148             }
149             //a+b==0或者1==a并且1==b时
150             if(-1==start)
151             {
152                 for(i=0;i<26;i++)
153                 {
154                     if(out[i])
155                         break;
156                 }
157                 start=i;
158             }
159             Eular(start, -1);
160             //输出
161             printf("%s", node[st.top()].str);
162             st.pop();
163             while(!st.empty())
164             {
165                  printf(".%s", node[st.top()].str);
166                  st.pop();
167             }
168             printf("\n");
169         }
170     }
171     return 0;
172 }

 

 

 

转载于:https://www.cnblogs.com/crazyapple/archive/2013/06/10/3131334.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值