POJ 2337 Catenyms(有向图欧拉路径判定&&打印)

15 篇文章 0 订阅
Catenyms
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 9905 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
***
这道题跟成语接龙很像,即第一个单词的最后一个字母和第二个单词的首字母是相同的,给你n个单词,问能否接起来,能并且不止一种的话,输出字典序最小的一个,没有输出"***"。。
首先,我们将这些单词转化为有向图,即一个单词为一条边,首字母为起点,最后一个字母为终点。
然后,对于一个有向图,是否存在欧拉路径,判定条件有两个,1、图是连通的(并查集) 2、每个点的入度=出度 或 只有两个点 入-出=1(终点) 出-入=1(起点)。。
最后,将按字典序排序后的每条边,从起点开始DFS,将所有的边遍历一遍,并记录下路径,即为最后结果。。
WA了一天,最后发现没有考虑所有点入度都等于出度的情况,sad~~
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#define M 30
#define N 1010
using namespace std;
struct node
{
    int x,y;           //每条边的起终点
    char s[M];         //记录每个单词
} q[N];
int n;                //单词数,即边数
int bin[N];
int in[M],out[M];     //入度,出度
int v[M],b[N];        //节点是否存在标志,边是否访问标志
int xx;               //起点
char ans[N][M];       //记录路径
int k;
int cmp(void const *a,void const *b)
{
    return strcmp((*(node*)a).s , (*(node*)b).s);
}
int findx(int x)
{
    int r=x;
    while(bin[r]!=r)
        r=bin[r];
    return r;
}
void merge(int x,int y)
{
    int fx,fy;
    fx=findx(x);
    fy=findx(y);
    if(fx!=fy)
        bin[fx]=fy;
}
bool connect()
{
    for(int i=0; i<26; i++)              //并查集判定是否连通
    {
        if(v[i])
        {
            for(int j=i+1; j<26; j++)
                if(v[j] && findx(i)!=findx(j))
                    return true;
            break;
        }
    }
    int s=0;                          
    for(int i=0; i<26; i++)            //判定是否有度不相等的情况
    {
        if(v[i])
        {
            if(in[i]!=out[i])
            {
                if(in[i]-out[i]==1||out[i]-in[i]==1)
                {
                    s++;
                    if(s>2)
                        return true;
                    if(out[i]-in[i]==1) xx=i;        //找到起点
                }
                else  return true;
            }
        }
    }
    if(xx==-1)                          //没有找到起点,说明所有点入度=出度,所有最小的节点当起点
    {
        for(int i=0; i<26; i++)         //就是缺了这个判断WA了一天。。。。。
        {
            if(v[i])
            {
                xx=i;
                break;
            }
        }
    }
    return false;
}
void dfs(int r)
{
    for(int i=0; i<n; i++)
    {
        if(!b[i] && q[i].x==r)     //找到该边且未访问过
        {
            b[i]=1;                 //标记访问
            dfs(q[i].y);            //从该边的终点继续往下寻找
            strcpy(ans[k++],q[i].s);     //记录路径,用来输出
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0; i<26; i++)
            bin[i]=i;
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(v,0,sizeof(v));
        for(int i=0; i<n; i++)
        {
            scanf("%s",q[i].s);
            int len=strlen(q[i].s);
            q[i].x=q[i].s[0]-'a';
            q[i].y=q[i].s[len-1]-'a';
            out[q[i].x]++;              //出度+1
            in[q[i].y]++;               //入度+1
            v[q[i].x]=1;                //标记该节点存在
            v[q[i].y]=1;
            merge(q[i].x,q[i].y);       
        }
        xx=-1;                          //初始化起点
        qsort(q,n,sizeof(q[0]),cmp);    //按字典序排序
        if(connect())                   //图是否连通 && 是否存在欧拉路径
        {
            printf("***\n");
            continue;
        }
        k=0;
        memset(b,0,sizeof(b));        //边访问标记
        dfs(xx);                      //从起点开始遍历每条边
        for(int i=k-1; i>=1; i--)
            printf("%s.",ans[i]);
        printf("%s\n",ans[0]);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值