poj 2337 Catenyms 判断并输出欧拉路 判断N个字符串是否能够首尾相连全部输出(欧拉路)

本文介绍了一种解决复合Catenym问题的算法实现,该算法通过构建图结构并运用并查集、欧拉路径等概念来寻找字典中所有单词组成的最小子序列。文章详细阐述了算法流程及关键步骤,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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
***

//



#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=10000;
int V,E;//点数 边数
struct edge
{
    int t;//s->t=w
    char w[30];
    int next;
};
int p[maxn];//表头节点
edge G[maxn];//邻接表
void addedge(int u,int v,char* w,int l)//u->v=w, 邻接表节点 l
{
    //cout<<u<<".."<<v<<".."<<w<<".."<<l<<endl;
    strcpy(G[l].w,w);
    G[l].t=v;
    //G[l].next=p[u];
    //p[u]=l;
    //按照w从小到大排序
    if(p[u]==-1)
    {
        G[l].next=p[u];
        p[u]=l;
        return ;
    }
    int index=-1,pre=-1;
    for(int i=p[u];i!=-1;i=G[i].next)
    {
        //cout<<"ok"<<endl;
        if(strcmp(G[i].w,w)>=0)
        {
            index=i;
            break;
        }
        pre=i;
    }
    if(pre==-1)
    {
        G[l].next=p[u];
        p[u]=l;
        return ;
    }
    //cout<<pre<<"..."<<index<<endl;
    G[l].next=G[pre].next;
    G[pre].next=l;
}


//并查集 判断弱连通
int fath[maxn];
int find(int x)
{
    return fath[x]==x?x:fath[x]=find(fath[x]);
}
void uion(int x,int y)
{
    x=find(x);y=find(y);
    if(x==y) return ;
    fath[x]=y;
}
//欧拉路
int in[maxn],out[maxn];//入度 出度
int flag;//判断是否存在欧拉路
int s0,t0;//欧拉路出发点  终结点
int ans[maxn];//保存欧拉路
int cur;//欧拉路长度
bool used[maxn];//判断边是否用过
///输出欧拉路
void dfs(int x,int cas)//顶点 边
{
    for(int i=p[x];i!=-1;i=G[i].next)
    {
        if(!used[i])
        {
            used[i]=1;
            dfs(G[i].t,i);
        }
    }
    if(cas!=-1) ans[cur++]=cas;
}
void print()//逆序输出
{
    for(int i=cur-1;i>0;i--)
    {
        printf("%s.",G[ans[i]].w);
    }printf("%s/n",G[ans[0]].w);
}
int main()
{
    int ci;scanf("%d",&ci);
    while(ci--)
    {
        scanf("%d",&E);V=26;
        memset(p,-1,sizeof(p));
        for(int i=1;i<=V;i++) fath[i]=i;
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(used,0,sizeof(used));
        char ch[25];int vis[27]={0};
        for(int i=0;i<E;i++)
        {
            scanf("%s",ch);
            int u=ch[0]-'a'+1,v=ch[strlen(ch)-1]-'a'+1;
            uion(u,v);vis[u]=vis[v]=1;
            in[v]++,out[u]++;
            addedge(u,v,ch,i);//w按照从小到大排序
        }
        flag=1;
        //判断弱连通
        int f1=-1;
        for(int i=1;i<=V;i++)
        {
            if(vis[i])
            {
                if(f1==-1) f1=find(i);
                else
                {
                    if(f1!=find(i))
                    {
                        flag=0;
                        break;
                    }
                }
            }
        }
        if(!flag) {printf("***/n");continue;}
        int ns0=0,nt0=0;//个数  >1时不存在欧拉路
        for(int i=1;i<=V;i++)
        {
            if(!vis[i]) continue;
            if(in[i]<out[i])
            {
                if(out[i]-in[i]==1) ns0++,s0=i;
                else flag=0;
            }
            else if(in[i]>out[i])
            {
                if(in[i]-out[i]==1) nt0++,t0=i;
                else flag=0;
            }
        }
        if(!(ns0<=1&&nt0<=1&&ns0==nt0)) flag=0;
        if(!flag) {printf("***/n");continue;}
        if(ns0==1)
        {
            cur=0;
            dfs(s0,-1);
        }
        else
        {
            cur=0;
            for(int i=1;i<=V;i++)
            {
                if(vis[i])
                {
                    dfs(i,-1);
                    break;
                }
            }
        }
        print();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值