zoukankan      html  css  js  c++  java
  • Catenyms

    【题目描述】

    现给定一组单词,如果存在某两个单词,一个单词的前缀和另一个单词的后缀相同,则认为这两个单词可以相连,例如“abce”与“efdg”可以相连,询问这组单词能否排成一排,如果可以,则输出字典序最小的排列方式。

    【输入描述】

    输入多组数据,对于每组数据:

    第一行输入一个正整数N(3 <= N <= 1000),表示此组单词的数目;

    接下来N行,每行输入一个单词,每个单词的长度不超过20。

    【输出描述】

    对于每组输入数据,输出一行,表示排列方式,每两个单词之间用一个“.”隔开,如果不存在合法的排列方式,则输出“***”。

    【输入样例】

    2

    6

    aloha

    arachnid

    dog

    gopher

    rat

    tiger

    3

    oak

    maple

    elm

    【输出样例】

    aloha.arachnid.dog.gopher.rat.tiger

    ***

    源代码:
    
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    struct Node
    {
        int To,Next,Number;
        bool Flag;
    }Edge[2001];
    int T,n,Num,Sum,In[30],Out[30],Head[30],Ans[1001];
    string S[1001];
    void Add(int t1,int t2,int Number) //边表。
    {
        Edge[++Num].To=t2;
        Edge[Num].Next=Head[t1];
        Edge[Num].Number=Number; //所属单词编号。
        Edge[Num].Flag=false;
        Head[t1]=Num;
    }
    void DFS(int T) //深搜。
    {
        for (int a=Head[T];a;a=Edge[a].Next) //注意顺序,值得学习,倒序遍历,故字典序最小。
          if (!Edge[a].Flag)
          {
            Edge[a].Flag=true;
            DFS(Edge[a].To);
            Ans[Sum++]=Edge[a].Number; //记录。
          }
    }
    int main()
    {
        cin>>T;
        while (T--)
        {
            cin>>n;
            for (int a=0;a<n;a++)
              cin>>S[a];
            sort(S,S+n); //按照字典序排序。
            Num=Sum=0;
            memset(In,0,sizeof(In));
            memset(Out,0,sizeof(Out));
            memset(Head,0,sizeof(Head));
            int Start=26;
            for (int a=n-1;a>=0;a--) //字典序大的先加入。
            {
                int t1=S[a][0]-'a'; //开头。
                int t2=S[a][S[a].length()-1]-'a'; //结尾。
                Add(t1,t2,a); //在首位之间建立一条有向边。
                Out[t1]++; //出度。
                In[t2]++; //入度。
                Start=min(Start,min(t1,t2)); //字典序最小的字母。
            }
            int T1(0),T2(0);
            for (int a=0;a<26;a++)
              if (Out[a]-In[a]==1) //只能最先出。
              {
                T1++;
                Start=a; //按照欧拉回路,如果有一个出度比入度大1的点,就从这个点出发,否则从字典序最小的点出发。
              }
              else
                if (Out[a]-In[a]==-1) //只能最后进。
                  T2++;
                else
                  if (Out[a]-In[a]) //怎么着都不合法了。
                    T1=2;
            if (!((!T1&&!T2)||(T1==1&&T2==1))) //若不为欧拉图或半欧拉图,则退出。
            {
                cout<<"***"<<endl;
                continue;
            }
            DFS(Start);
            if (Sum!=n) //判断是否连通。
            {
                cout<<"***"<<endl;
                continue;
            }
            for (int a=Sum-1;a>=0;a--) //输出。
            {
                cout<<S[Ans[a]];
                if (a)
                  cout<<".";
                else
                  cout<<endl;
            }
        }
        return 0;
    }
    
    /*
        解题思路:
            其实把首尾两个字母作为节点建图,跑欧拉回路就可以了,中间的字母只是用来字典序排序的,并没有用到。
    */
  • 相关阅读:
    管理学课程都包括哪些方面的内容?
    关于如何创业的好书推荐:《创业必读12篇》
    关于企业文化的书籍,这本最经典
    如何开展行政管理工作?这些书可以告诉你答案
    企业家必读书籍有哪些?适合企业高管看的书推荐
    如何学好PHP?
    现在入门还有必要学PHP吗?
    Python实现递归二分法查找
    SAP Control framework–CL_GUI_TOOLBAR
    SAP Control framework–DIALOGBOX_CONTAINER
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5925421.html
Copyright © 2011-2022 走看看