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

来源:互联网 发布:java知识分享网 编辑:程序博客网 时间:2024/05/29 03:40
Catenyms
Time Limit: 1000MS Memory Limit: 65536KTotal 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.gophergopher.ratrat.tigeraloha.alohaarachnid.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

26alohaarachniddoggopherrattiger3oakmapleelm

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 1010using 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
原创粉丝点击