POJ 2337 Catenyms(有向欧拉图:输出欧拉路径)

题目链接>>>>>>

题目大意:

给出一些字符串,问能否将这些字符串  按照 词语接龙,首尾相接  的规则 使得每个字符串出现一次

如果可以 按字典序输出这个字符串序列

#include <iostream>  
#include <cstdio> 
#include <string>
#include <cstring>  
#include <vector>  
#include <algorithm>  
#define M 1050  
using namespace std;
int n, top;
struct edge {
    int to, vis, id;           //to代表边的终点,id代表边的编号
};
vector<edge>w[M];
string str[M];                //原来还可以这样定义字符串数组
int ans[M];
int fa[29];

int find(int x)
{
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}

void fleury(int loc)
{
    for (int i = 0; i<w[loc].size(); i++)
        if (!w[loc][i].vis)
        {
            w[loc][i].vis = 1;
            fleury(w[loc][i].to);
            ans[top++] = w[loc][i].id;
        }
    return;
}

int main()
{
    int indegree[28], outdegree[28];
    int T;
    scanf("%d", &T);
    while (T--)
    {
        top = 0;
        for (int i = 0; i<26; i++)
        {
            w[i].clear();
            outdegree[i] = indegree[i] = 0;
            fa[i] = i;
        }
        scanf("%d", &n);
        int a, b;
        for (int i = 0; i<n; i++)
            cin >> str[i];
        sort(str, str + n);             //根据字典序排序  
        edge edg;
        int start;
        for (int i = 0; i<n; i++)
        {
            a = str[i][0] - 'a';
            b = str[i][str[i].size() - 1] - 'a';
            indegree[a]++;
            outdegree[b]++;
            fa[find(a)] = find(b);     
            edg.to = b; edg.vis = 0; edg.id = i;
            w[a].push_back(edg);
            if (i == 0)              //重要  起点必须为初始化为第一条边的出节点(字典序最小,且满足 欧拉回路 的的要求)  
                start = a;
        }

        int ss = 0, num = 0, start_num = 0, end_num = 0;
        for (int i = 0; i<26; i++)
        {
            if ((indegree[i] || outdegree[i]) && find(i) == i)          //find(i)==i是用来判断整个图是否连通的,因为图存在欧拉通路的条件之一就是必须是连通图
                ss++;                                                   //结合下面的ss==1,来理解,因为如果整个图是连通的,ss就只会在当i为根节点的时候+1
            if (indegree[i] != outdegree[i])
            {
                if (outdegree[i] - indegree[i] == -1)
                    start = i, start_num++;                         //这里和上面的初始化start的步骤不懂,做题的时候就是卡在了选取第一个出节点的步骤
                else if (outdegree[i] - indegree[i] == 1)
                    end_num++;
                num++;
            }
        }
        if ((num == 0 || (num == 2 && start_num == 1 && end_num == 1)) && ss == 1)           //存在欧拉通路的条件
        {
            fleury(start);                 //我对start的选取不是很理解
            for (int i = top - 1; i >= 0; i--)             //要使输出的单词按字典序输出
            {
                if (i == 0)
                    cout << str[ans[i]] << endl;
                else
                    cout << str[ans[i]] << ".";
            }
        }
        else
            cout << "***" << endl;
    }
    return 0;
}

2018-04-07


作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/00isok/p/8734550.html