POJ 2337 Catenyms (有向图欧拉通路)

91 篇文章 1 订阅

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:
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,本题边很少,所以可以直接通过边来找

#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");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值