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("\n");

        }

        else

            puts("***");

    }

    return 0;

}
View Code

 

 

你可能感兴趣的:(路径)