POJ 2337 Catenyms 欧拉回路

Catenyms
Time Limit: 1000MS      Memory Limit: 65536K
Total Submissions: 11660        Accepted: 3037

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

Source
Waterloo local 2003.01.25

http://blog.csdn.net/LuRiCheng/article/details/52415262的升级版
如果把字母当做点
把单词当做边 例如:dog=>从d到g的有向边
建图后 不难发现 这其实就是欧拉回路的变种 一笔画问题
至于输出回路 dfs即可
PS:POJ不支持string.back() 真蛋疼

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<time.h>
#include<math.h>
#include<list>
#include<cstring>
#include<fstream>
//#include<memory.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define INF 1000000007
#define pll pair<ll,ll>
#define pid pair<int,double>

const int N=1000+5;//最大边数
vector<string>vec;//边
int inDegree[26];//入度
int outDegree[26];//出度
int par[26];//并查集
vector<int>G[26];//邻接表 G[i]保存从i出发的边的下标 下标按边的字典序排序
bool used[N];//dfs标记
deque<string>ans;//答案

inline int find(int i){
    return par[i]=(par[i]==i?i:find(par[i]));
}

inline void unite(int i,int j){
    par[find(i)]=find(j);
}

void builtG(){
    for(int i=0;i<26;++i)
        G[i].clear();
    //对边进行排序 dfs时按顺序搜索 找到的第一个合法回路就是字典序最小的回路
    sort(vec.begin(),vec.end());
    for(int i=0;i<vec.size();++i){
        int st=vec[i][0]-'a';
        G[st].push_back(i);
    }
}

void dfs(int in){
    for(int i=0;i<G[in].size();++i){
        int strIndex=G[in][i];
        if(!used[strIndex]){
            used[strIndex]=true;
            int to=vec[strIndex][vec[strIndex].size()-1]-'a';
            dfs(to);
            ans.push_front(vec[strIndex]);
        }
    }
}

int main()
{
    //freopen("/home/lu/文档/r.txt","r",stdin);
    //freopen("/home/lu/文档/w.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        vec.clear();
        vec.resize(n);
        //ini
        fill(inDegree,inDegree+26,0);
        fill(outDegree,outDegree+26,0);
        for(int i=0;i<26;++i)
            par[i]=i;
        for(int i=0;i<n;++i){
            cin>>vec[i];
            int st=vec[i][0]-'a';
            int end=vec[i][vec[i].size()-1]-'a';
            ++outDegree[st];
            ++inDegree[end];
            unite(st,end);
        }

        //check is-unicom
        int numOfSet=0;//检测所有边是否在一个联通集合中
        for(int i=0;i<26;++i)
            numOfSet+=(inDegree[i]+outDegree[i]>0&&par[i]==i);
        if(numOfSet>1){
            printf("***\n");
            continue;
        }

        //check inDegree and outDegree
        int in=-1,out=-1;//检测入度出度是否符合一笔画
        bool noResult=false;
        for(int i=0;i<26;++i){
            int dt=inDegree[i]-outDegree[i];
            if(dt==1){
                if(out>=0){
                    noResult=true;
                    break;
                }
                out=i;
            }
            else
                if(dt==-1){
                    if(in>=0){
                        noResult=true;
                        break;
                    }
                    in=i;
                }
                else
                    if(dt!=0){
                        noResult=true;
                        break;
                    }

        }
        if(noResult){
            printf("***\n");
            continue;
        }
    //dfs找出回路
        fill(used,used+n,false);
        builtG();
        ans.clear();
        if(in>=0)
            dfs(in);
        else
            for(int i=0;i<26;++i)
                if(inDegree[i]>0){
                    dfs(i);
                    break;
                }
        cout<<ans.front();
        for(int i=1;i<ans.size();++i)
            cout<<"."<<ans[i];
        cout<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值