poj 2337 Catenyms(欧拉路径的最小字典序)

Catenyms
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 8505 Accepted: 2237

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
***
 
题意:给出n个单词,若一个单词的末尾字母和另一个单词的首字母相同,则它们可以连在一起。问是否能将这n个单词都连成一串序列,若能,输出字典序最小的序列。
思路:将每个单词的首字母和末尾字母分别看出一个点,单词看成是边,转化为求有向图的欧拉路径。有向图的欧拉路径存在的充要条件为所有点的出度==入度,或有一个点的出度-入度=1且有一个点的入度-出度=1。判断完是否存在欧拉路径后,就对单词进行排序,这里用邻接表排序。最后进行dfs,若所有点的出度==入度,则从字典序最小的点开始dfs,否则,从出度-入度=1的点开始dfs。
 
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <map>
#include <cstdlib>
#define L(rt) (rt<<1)
#define R(rt) (rt<<1|1)
#define ll long long
#define eps 1e-6
using namespace std;

const int maxn=1005;
struct node
{
    int v;
    bool vis;
    char str[25];
} edge;
vector<node>G[30];
stack<char *>print;
int in[30],out[30],fa[30],st;
bool vis[30];
int n;
bool cmp(node a,node b)
{
    return strcmp(a.str,b.str)<0;
}
void init()
{
    memset(vis,false,sizeof(vis));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    for(int i=0; i<30; i++)
    {
        fa[i]=i;
        G[i].clear();
    }
    st=-1;
}
int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
void Union(int a,int b)
{
    fa[find(a)]=find(b);
}
bool judge()
{
    int cnt=0;
    for(int i=0; i<26; i++)
        if(vis[i]&&fa[i]==i) cnt++;
    if(cnt>1) return false;
    int cnt1=0,cnt2=0;
    for(int i=0; i<26; i++)
    if(vis[i])
    {
        if(in[i]==out[i]) continue;
        else if(in[i]-out[i]==1) cnt1++;
        else if(out[i]-in[i]==1)
        {
            cnt2++;
            st=i;
        }
        else return false;
    }
    if((cnt1==0&&cnt2==0)||(cnt1==1&&cnt2==1)) return true;
    return false;
}
void dfs(int u)
{
    for(int i=0;i<(int)G[u].size();i++)
    {
        int v=G[u][i].v;
        if(!G[u][i].vis)
        {
            G[u][i].vis=true;
            dfs(v);
            print.push(G[u][i].str);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%s",edge.str);
            int len=strlen(edge.str);
            int a=edge.str[0]-'a';
            int b=edge.str[len-1]-'a';
            vis[a]=vis[b]=true;
            edge.v=b;
            edge.vis=false;
            G[a].push_back(edge);
            out[a]++;
            in[b]++;
            Union(a,b);
        }
        if(!judge())
        {
            printf("***\n");
            continue;
        }
        for(int i=0; i<26; i++)
            if(vis[i]) sort(G[i].begin(),G[i].end(),cmp);
        if(st==-1)
        {
            for(int i=0; i<26; i++)
                if(vis[i])
                {
                    dfs(i);
                    break;
                }
        }
        else dfs(st);
        char *s=print.top();
        print.pop();
        printf("%s",s);
        while(!print.empty())
        {
            s=print.top();
            print.pop();
            printf(".%s",s);
        }
        puts("");
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值