Catenyms
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 12020 | Accepted: 3121 |
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
***
Source
Waterloo local 2003.01.25
题意:给你一些单词,如果一个单词的末尾字符与另一个单词首字符相同,则两个的单词可以连接。问是否可以把所有单词连接起来,并且每个单词只能用一次。
这道题要用到欧拉通路。那么什么是欧拉通路呢?
欧拉回路与欧拉通路:
通过图(无向图或有向图)中所有边且每边仅通过一次通路称为欧拉通路,相应的回路称为欧拉回路。具有欧拉回路的图称为欧拉图(Euler Graph)
1.图的连通性
无论是有向图还是无向图,在判断是否存在欧拉回路或者欧拉通路的时候,都要满足图是连通的,也就是说我们要先判断图的连通性。
2.判断是否存在欧拉通路或欧拉回路
(1).判断是否存在欧拉通路
有向图:图连通,有一个点的出度比入度大一(此为始点),有一个点的入度比出度大一(此为终点),其余点如度等于出度
无向图:图连通,只有两个点的度数是奇数度(始点和终点),其余的都是偶数度。
(2).判断是否存在欧拉回路
有向图:图连通,所有点的入度等于出度
无向图:所有点的度数都是偶数度。
3.输出欧拉路径
利用DFS保存下欧拉路径。
这道题是有向图的欧拉通路,根据上面的思路,就可以完美解决了。
AC代码:
对于欧拉回路的理解还比较浅,欢迎评论。
题意:给你一些单词,如果一个单词的末尾字符与另一个单词首字符相同,则两个的单词可以连接。问是否可以把所有单词连接起来,并且每个单词只能用一次。
这道题要用到欧拉通路。那么什么是欧拉通路呢?
欧拉回路与欧拉通路:
通过图(无向图或有向图)中所有边且每边仅通过一次通路称为欧拉通路,相应的回路称为欧拉回路。具有欧拉回路的图称为欧拉图(Euler Graph)
1.图的连通性
无论是有向图还是无向图,在判断是否存在欧拉回路或者欧拉通路的时候,都要满足图是连通的,也就是说我们要先判断图的连通性。
2.判断是否存在欧拉通路或欧拉回路
(1).判断是否存在欧拉通路
有向图:图连通,有一个点的出度比入度大一(此为始点),有一个点的入度比出度大一(此为终点),其余点如度等于出度
无向图:图连通,只有两个点的度数是奇数度(始点和终点),其余的都是偶数度。
(2).判断是否存在欧拉回路
有向图:图连通,所有点的入度等于出度
无向图:所有点的度数都是偶数度。
3.输出欧拉路径
利用DFS保存下欧拉路径。
这道题是有向图的欧拉通路,根据上面的思路,就可以完美解决了。
AC代码:
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int out[30], in[30], step[1001], pre[30];///in表示入度 out表示出度 step用来保存最后的路径 pre保存i的父节点
char str[30];
struct Edge
{
int s, e; ///s是单词的第一个字符 e是最后一个字符
int v; ///用来标记当前的单词是否用过
char str1[30];
}edge[1001];
int st, k, n;
bool cmp(Edge x, Edge y)
{
return strcmp(x.str1, y.str1) < 0? true : false;
}
int Find(int x) ///利用并查集把所有点都加到一个集合中
{
while(pre[x]!=x)
x = pre[x];
return x;
}
int judge() ///判断连通性
{
int fx = Find(edge[1].s);
for(int i = 1; i <= 26; i++)
{
if(out[i] > 0||in[i] > 0)
{
if(fx != Find(i))
return 0;
}
}
return 1;
}
void DFS(int End) ///把路径保存下来
{
for(int i = 1; i <= n; i++)
{
if(edge[i].v==0&&edge[i].s==End)
{
edge[i].v = 1;
DFS(edge[i].e);
step[k++] = i;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int i;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(step, 0, sizeof(step));
for(i = 1; i <= 30; i++) ///入度为本身
pre[i] = i;
scanf("%d",&n);
for(i = 1; i <= n; i++)
{
cin >> str;
int len = strlen(str);
int s = str[0] - 'a' + 1;
int e = str[len - 1] - 'a' + 1;
edge[i].s = s;
edge[i].e = e;
edge[i].v = 0;
strcpy(edge[i].str1, str);
out[s]++;
in[e]++;
int fx = Find(s);
int fy = Find(e);
if(fx!=fy)
pre[fx] = fy;
}
sort(edge + 1, edge + n + 1, cmp);
///题目要求字典序最小输出,就先按从小到大的顺序把边(单词)排好
/**st代表的是路径起点,在这里进行st = edge[1].s赋值,是应为存在两种情况:
1.存在一定点出度>入度,这个点是起点。
2.所有点出度= 入度,
那么从任意一点出发都可以, 为了保证字典序最小, 就从第一个单词开始**/
st = edge[1].s;
int c1 = 0, c2 = 0;
for(i = 1; i <= 26; i++) ///判断是否有欧拉回路
{
if(out[i]==in[i]) continue;
if(out[i]-in[i]==1)
{
c1++;
st = i; ///把起点给st
}
else if(out[i] - in[i] == -1)
c2++;
else break;
}
///如果图是连通的 并且存在欧拉回路 那么开始找路径
if(i==27&&((c1==0&&c2==0)||(c1==1&&c2==1))&& judge()==1)
{
k = 1;
DFS(st);
for(int i = n; i > 1; i--) ///注意 我们用递归求得路径 第一个保存的是最后一个
printf("%s.",edge[step[i]].str1);
printf("%s\n",edge[step[1]].str1);
}
else
printf("***\n");
}
return 0;
}
对于欧拉回路的理解还比较浅,欢迎评论。