Catenyms+欧拉回路/欧拉路+并查集+POJ

Catenyms

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9617   Accepted: 2524

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
***
解决方案:首先建立一个图的模型:用单词的首尾字母做节点,用单词做边。这些单词能连成一串,必须:1)能形成欧拉路或欧拉回路;2)要能构成一个连通图。先是判断是欧拉回路/欧拉路:记录每个顶点的出度与入度,若有一个点出度大入度1,一个点入度大出度1,其余出度等于入度,则为欧拉路;若每个店的出度与入度都相等,则为欧拉回路。然后判断是否为联通的,可用并查集来判断,这个就不用说了。然后是怎么建图的问题,这个最好用头插法建图,记录每个顶点所连得边及终点。再则就是输出要字典序的问题,可以这样子,先对单词进行排序,然后按照排好顺序的单词建图,是要从小到大,还是从大到小排呢。若是从小到大,由于是头插法建图,那么每次遍历边的时候,这个按字典序从大到小来遍历的,所以,我们应该从大到小排序。还有就是起点的问题:若是欧拉路,则出度比入度大1的那个点做起点,若是欧拉回路,字典序最小的点做起点。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define MMAX 1003
using namespace std;
string word[MMAX];
int fa[27],in[27],out[27];
int Map[27][27];
bool vise[MMAX];
bool cmp(string a,string b)
{
    return a>b;
}
stack<string>S;
int N,k;
int head[27];
struct node
{
    int from,to;
    string word;
    int next;
} E[MMAX];
void add(int from,int to,string word)
{
    E[k].from=from;
    E[k].to=to;
    E[k].word=word;
    E[k].next=head[from];
    head[from]=k++;
}
bool vis[27];
int faset(int x)
{

    return x!=fa[x]?fa[x]=faset(fa[x]):x;
}
int C(char c)
{
    return int(c-'a');
}
void dfs(int v)
{
    for(int i=head[v]; i!=-1; i=E[i].next)
    {
        if(!vise[i])
        {
            vise[i]=true;
            dfs(E[i].to);
            S.push(E[i].word);

        }
    }

}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(head,-1,sizeof(head));
        memset(vis,false,sizeof(vis));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(Map,0,sizeof(Map));
        memset(vise,false,sizeof(vise));
        while(!S.empty())S.pop();
        for(int i=0; i<26; i++)
        {
            fa[i]=i;
        }
        scanf("%d",&N);
        for(int i=0; i<N; i++)
        {
            cin>>word[i];
        }
        sort(word,word+N,cmp);
        k=0;
        for(int i=0; i<N; i++)
        {
            int len=word[i].length();
            int st=C(word[i][0]),en=C(word[i][len-1]);
            add(st,en,word[i]);
            int x=faset(st),y=faset(en);
            vis[st]=true,vis[en]=true;
            if(x!=y)
            {
                fa[x]=y;
            }
            in[en]++,out[st]++;
        }
        bool flag=true;
        int pre=faset(C(word[0][0]));
        for(int i=0; i<26; i++)
        {
            if(vis[i])
            {
                if(pre!=faset(i))
                {
                    flag=false;
                    break;
                }
            }
        }
        int st,cst=0,cen=0,cnt=0;
        st=C(word[N-1][0]);
        for(int i=0; i<26; i++)
        {
            if(in[i]!=out[i])
            {
                if(abs(in[i]-out[i])>1)
                {
                    flag=false;
                    break;
                }
                if(in[i]+1==out[i]) cst++,st=i;

                if(out[i]+1==in[i]) cen++;
                cnt++;
            }
        }
        if((cst==1&&cen==1)||!cnt) ;
        else flag=false;
        if(flag)
        {
            dfs(st);
            while(!S.empty())
            {
                string temp=S.top();
                S.pop();
                cout<<temp<<".";
                if(S.size()==1) break;
            }
            cout<<S.top()<<endl;
            S.pop();
        }
        else
        {
            printf("***\n");
        }
    }
    return 0;
}

Catenyms+欧拉回路/欧拉路+并查集+POJ

时间: 2024-10-23 11:57:21

Catenyms+欧拉回路/欧拉路+并查集+POJ的相关文章

poj 1386 Play on Words(有向图欧拉路+并查集)

题目链接:http://poj.org/problem?id=1386 思路分析:该问题要求判断单词是否能连接成一条直线,转换为图论问题:将单词的首字母和尾字母看做一个点,每个单词描述了一条从首字母指向尾字母的有向边, 则则所有的单词构成了一个有向图,问题变为判断该有向图中是否存在一条欧拉路:有向图中存在欧拉路的两个充分必要条件为:该图是联通的并且所有的点的入度等于出度或者只存在两个点的入度与出度不等,一个点的入度=出度+1,另一个点的入度=出度-1: 代码如下: #include <cstdi

NYOJ42 一笔画问题 【欧拉回路】+【并查集】

一笔画问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来. 规定,所有的边都只能画一次,不能重复画. 输入 第一行只有一个正整数N(N<=10)表示测试数据的组数. 每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),分别表示这个画中有多少个顶点和多少条连线.(点的编号从1到P) 随后的Q行,每行有两个正整数A,B(0<

[并查集] POJ 2236 Wireless Network

Wireless Network Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 25022   Accepted: 10399 Description An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap compute

欧拉回路——欧拉路与欧拉回路

题目:欧拉路与欧拉回路 描述: 给一个无向图图,如果存在欧拉回路请从第一个点为起点开始遍历,如果存在欧拉路,则以字典序大的为起点开始遍历,在遍历的过程中,字典序小的先遍历,都不存在输出-1.注意两个点之间可能有多条边,请全部遍历,还有可能存在自环. [输入格式] 第一行N,E为点数和边数,后E行每行有两个数,表示他们之间存在一条无向边. [输出格式] 若干个数,表示遍历次序. [样例输入] 3 2 1 2 2 3 [样例输出] 3 2 1 [提示] N<=20 E<=500 解析:最近刚学了欧

[并查集] POJ 1182 食物链

食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 66294   Accepted: 19539 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同

并查集 POJ 1988 Cube Stacking

题目传送门:    -------->这里<---------- 题目大意: 有标记1-N的方块,初始时一个砖块是一堆.然后进行以下操作 M X Y : 将 X 砖块所在堆 叠到 Y 砖块所在堆上面: C X :数在 X 砖块所在堆中 叠在X砖块下的砖块个数: 1<=N<=30000; 思路: 并查集,每一个砖块堆是一个集合.将每一堆的最上面一块砖设为根,合并时更新 Y 堆的根的 father 和 val (在Y上面的方块数) . 要达到这些目的,需要一个all数组,来记录每一堆里

[并查集] POJ 1611 The Suspects

The Suspects Time Limit: 1000MS   Memory Limit: 20000K Total Submissions: 35206   Accepted: 17097 Description Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. T

并查集 POJ 1988

#include <cstdio> #define N 30010 int pa[N]; //parent int siz_tree[N]; //size of tree int d[N]; //dist between node and root int Find(int x) { if(pa[x] == x) return x; int t = pa[x]; pa[x] = Find(pa[x]); d[x] += d[t]; return pa[x]; } void Union(int

并查集 POJ 1703 Find them, Catch them

题目传送门 题意:有两个黑帮集团,给出一些两个小弟属于不同的黑帮,询问两个小弟是否关系能确定 分析:首先直接弄两个集合是不好的,正确的做法是类似食物链的做法,关系已确定不属于同一个帮派的x 和 y 使得x 和 y + n属于同一个集合,y 和 x + n属于同一个集合,那么最后只要判断x 和 y 是否在同一个集合就可以了 收获:关系的连通问题 代码: /************************************************ * Author :Running_Time