zoukankan      html  css  js  c++  java
  • UESTC 917 方老师的分身IV --求欧拉路径

    判断欧拉路径是否存在及求出字典序最小的欧拉路径问题(如果存在)。

    将字符串的第一个字母和最后一个字母间连边,将字母看成点,最多可能有26个点(a-z),如果有欧拉路径,还要判断是否有欧拉回路,如果有,则需要找一个字典序最小的点开始生成这条链,否则以起点开始生成链,起点即为出度比入度大1的点。

    欧拉路径是否存在的判定:

    1.全部点在一个联通块                               ----用并查集判联通块的数量
    2.所有点出度入度相等                               ----in[],out[]记录出度与入度
    3.或者有一个出度比入度小1,另一个出度比入度大1(源点与汇点)

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <string>
    #define Mod 1000000007
    using namespace std;
    #define N 2007
    
    string ss[N];
    
    struct node
    {
        int u,v,next;
        string w;
    }G[N];
    
    int first[28],fa[28],in[28],out[28],vis[28];
    int tot,k,start;
    int evis[N];
    string ans[N];
    
    void init()
    {
        int i;
        for(i=0;i<28;i++)
            fa[i] = i;
        tot = 1;
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(i=0;i<=2000;i++)
        {
            G[i].u = G[i].v = G[i].next = 0;
            G[i].w = "";
        }
        memset(first,-1,sizeof(first));
        memset(vis,0,sizeof(vis));
        memset(evis,0,sizeof(evis));
        for(int j=0;j<=2000;j++)
            ans[j] = "";
    }
    
    int findset(int x)
    {
        if(x != fa[x])
            fa[x] = findset(fa[x]);
        return fa[x];
    }
    
    int cmp(string ka,string kb)
    {
        return ka>kb;
    }
    
    void addedge(int u,int v,string w)
    {
        G[tot].u = u;
        G[tot].v = v;
        G[tot].w = w;
        G[tot].next = first[u];
        first[u] = tot++;
        out[u]++;
        in[v]++;
        vis[u] = vis[v] = 1;
        int fx = findset(u);
        int fy = findset(v);
        if(fx != fy)
            fa[fx] = fy;
    }
    
    int Euler_Path()
    {
        int block = 0,i;
        int O = 0;
        int I = 0;
        start = -1;
        for(i=0;i<26;i++)
        {
            if(vis[i])   //涉及到的字母
            {
                int fk = findset(i);
                if(fk == i)
                    block++;
                if(block > 1)
                    return false;
                if(in[i] == out[i]+1)  //入大出,奇度数点
                    I++;
                else if(in[i]+1 == out[i]) //出大入,奇度数点
                    O++,start = i;
                else if(in[i] != out[i])
                    return false;
            }
        }
        if(block != 1)
            return false;
        if((O == I && O == 1) || (O == I && O == 0)) //没有奇度数点或者只有源点和汇点是奇度数点
        {
            if(start == -1)   //没有找到起点,是欧拉回路
            {
                for(i=0;i<26;i++)
                {
                    if(vis[i] && out[i] > 0)  //找字典序最小的字母做起点
                    {
                        start = i;
                        return true;
                    }
                }
            }
            //如果已找到起点,则不能是欧拉回路
            if(O == I && O == 1)
                return true;
            return false;
        }
        return false;
    }
    
    void dfs(int v,int flag)
    {
        for(int e=first[v];e!=-1;e=G[e].next)
        {
            if(!evis[e])  //边没被访问
            {
                evis[e] = 1;
                dfs(G[e].v,e);
            }
        }
        if(flag != -1)
            ans[k++] = G[flag].w;
    }
    
    int main()
    {
        int t,i,j,n;
        scanf("%d",&t);
        while(t--)
        {
            init();
            scanf("%d",&n);
            for(i=1;i<=n;i++)
                cin>>ss[i];
            sort(ss+1,ss+n+1,cmp);
            //qsort(ss+1,n,28,cmp);
            for(i=1;i<=n;i++)
            {
                int u = ss[i][0]-'a';
                int v = ss[i][ss[i].length()-1]-'a';
                addedge(u,v,ss[i]);
            }
            if(Euler_Path())
            {
                k = 0;
                dfs(start,-1);
                cout<<ans[k-1];
                for(i=k-2;i>=0;i--)
                    cout<<"."<<ans[i];
                printf("
    ");
            }
            else
                puts("***");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [转] css选择器中:first-child与:first-of-type的区别
    [转] Javascript中理解发布--订阅模式
    [转] 浅析JavaScript设计模式——发布-订阅/观察者模式
    [转] linux学习第四十四篇:Nginx安装,Nginx默认虚拟主机,Nginx域名重定向
    [转] meta标签的作用及整理
    [转] 安装npm全局包提示权限不够
    [转] UniCode编码表
    Unicode字符编码表
    [转] Lodash常用API笔记
    [转] JavaScript 之 ArrayBuffer
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3765446.html
Copyright © 2011-2022 走看看