Catenyms
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 9914 | Accepted: 2588 |
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
题目链接:http://poj.org/problem?id=2337
题目大意:t组样例,每组n个字符串,如果一个字符串的尾字符和另一个的头字符相同则可以连接,问能不能将这n个都连接起来,能的话按要求输出结果,不能输出***
题目分析:本题构图思路很简单,一个字符串的第一个字符和最后一个字符为结点,字符串本身为边,因为本题没说连通,我们要先用并查集判连通,若根不唯一则说明不连通,接着就是看点的出入度,某结点出入度相差大于1或相差等于1的多于2个则不存在欧拉通路,否则若存在欧拉通路,则把出度比入度大1的结点当起点,若存在欧拉回路,则取字典序最小的做为起点。本体要求最后答案的字典序最小,因此我们再判断前要先对字符串由小到大排序,至于找通路,直接DFS,本题边很少,所以可以直接通过边来找
题目链接:http://poj.org/problem?id=2337
题目大意:t组样例,每组n个字符串,如果一个字符串的尾字符和另一个的头字符相同则可以连接,问能不能将这n个都连接起来,能的话按要求输出结果,不能输出***
题目分析:本题构图思路很简单,一个字符串的第一个字符和最后一个字符为结点,字符串本身为边,因为本题没说连通,我们要先用并查集判连通,若根不唯一则说明不连通,接着就是看点的出入度,某结点出入度相差大于1或相差等于1的多于2个则不存在欧拉通路,否则若存在欧拉通路,则把出度比入度大1的结点当起点,若存在欧拉回路,则取字典序最小的做为起点。本体要求最后答案的字典序最小,因此我们再判断前要先对字符串由小到大排序,至于找通路,直接DFS,本题边很少,所以可以直接通过边来找
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct EDGE
{
char s[25];
int x, y;
}e[1005];
bool has[30], vis[1005];
int in[30], out[30], fa[30], ans[1005];
int n, st, len;
bool cmp(EDGE a, EDGE b)
{
return strcmp(a.s, b.s) < 0;
}
int abs(int x)
{
return x > 0 ? x : -x;
}
int change(char ch)
{
return int(ch - 'a' + 1);
}
void UF_set()
{
for(int i = 0; i < 200; i++)
fa[i] = i;
}
int Find(int x)
{
return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
void Union(int a, int b)
{
int r1 = Find(a);
int r2 = Find(b);
if(r1 != r2)
fa[r1] = r2;
}
bool exist()
{
int t = -1;
for(int i = 1; i <= 26; i++)
{
if(has[i])
{
if(t == -1)
t = Find(i);
if(t != Find(i))
return false;
}
}
int sum = 0, tmp = 100;
for(int i = 1; i <= 26; i++)
{
if(has[i])
{
tmp = min(tmp, i);
if(in[i] != out[i])
{
if(abs(in[i] - out[i]) > 1)
return false;
if(out[i] > in[i])
st = i;
sum ++;
}
}
}
if(sum > 2)
return false;
if(sum == 0)
st = tmp;
return true;
}
void DFS(int now)
{
for(int i = 0; i < n; i++)
{
if(!vis[i] && e[i].x == now)
{
vis[i] = true;
DFS(e[i].y);
ans[len++] = i;
}
}
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
st = 0;
UF_set();
memset(has, false, sizeof(has));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%s", e[i].s);
e[i].x = change(e[i].s[0]);
e[i].y = change(e[i].s[(int)strlen(e[i].s) - 1]);
has[e[i].x] = true;
has[e[i].y] = true;
in[e[i].y] ++;
out[e[i].x] ++;
Union(e[i].x, e[i].y);
}
sort(e, e + n, cmp);
if(exist())
{
len = 0;
memset(vis, false, sizeof(vis));
DFS(st);
for(int i = len - 1; i > 0; i--)
printf("%s.", e[ans[i]].s);
printf("%s\n", e[ans[0]].s);
}
else
printf("***\n");
}
}