首页 > 代码库 > poj 2337(单向欧拉路的判断以及输出)

poj 2337(单向欧拉路的判断以及输出)

Catenyms
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 11648   Accepted: 3036

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,终点:入度-出度=1,其它点:入度==出度

  有向欧拉回路:所有点:入度==出度

  还要利用并查集判断一下这个图是否只有一个连通分量.

  然后将所有的边按照字典序排序,找到起点,进行DFS(Edge &e = edge[u][i] 这里检查了半天,一点要记得是地址啊...),即可得到答案.

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
#include <stack>
using namespace std;
const int N = 2222;
char str[100];
struct Edge{
    char str[100];
    int to,del;
};

typedef vector <Edge> vec;
stack <string> ans;
vec edge[N];
int in[N],out[N],father[N];
bool vis[N],mark[30];
int n;
void init(){
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=30;i++){
        mark[i] = false;
        edge[i].clear();
        father[i] = i;
    }
}
int _find(int x){
    return x==father[x]?x:father[x] = _find(father[x]);
}

void dfs(int u){
    for(int i=0;i<edge[u].size();i++){
        Edge &e = edge[u][i];  ///这里要取地址
        int v = e.to;
        if(!e.del){
            e.del = 1;
            dfs(v);
            ans.push(e.str);
        }
    }
}
bool cmp(Edge a,Edge b){
    return strcmp(a.str,b.str)<0;
}
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--){
        init();
        scanf("%d",&n);
        int S = N;
        for(int i=1;i<=n;i++){
            scanf("%s",str);
            int s = str[0]-a+1;
            int t = str[strlen(str)-1]-a+1;
            Edge e;
            e.del = 0;
            strcpy(e.str,str);
            e.to = t;
            edge[s].push_back(e);
            in[t]++;
            out[s]++;
            mark[t] = mark[s] = 1;
            int u = _find(s);
            int v = _find(t);
            if(u!=v) father[u] = v;
            S = min(S,min(s,t));
        }
        int num1 = 0,num2 = 0,num3 = 0,num4 = 0;
        for(int i=1;i<=26;i++){
            if(mark[i]==1&&father[i]==i) num4++;
            if(out[i]-in[i]==1){
                S = i;
                num1++;
            }
            else if(in[i]-out[i]==1){
                num2++;
            }else if(in[i]-out[i]!=0){
                num3++;
            }
            if(!edge[i].empty())
            sort(edge[i].begin(),edge[i].end(),cmp);
        }
        if(num3||!(num1==1&&num2==1)&&!(num1==0&&num2==0)||num4>1){
            printf("***\n");
            continue;
        }
       dfs(S);
       int flag = 0;
       while(!ans.empty()){
            if(flag) printf(".");
            cout<<ans.top();
            flag = 1;
            ans.pop();
        }
        printf("\n");
    }
}

 

poj 2337(单向欧拉路的判断以及输出)