UVA-10129 Play on Words (判断欧拉道路的存在性)

题目大意:给出一系列单词,当某个单词的首字母和前一个单词的尾字母相同,则这两个单词能链接起来。给出一系列单词,问是否能够连起来。

题目分析:以单词的首尾字母为点,单词为边建立有向图,便是判断图中是否存在欧拉道路。有向图中存在欧拉路径的两个条件是:1、忽略边的方向性后,底图联通;2、奇点个数为0时、奇点个数为2并且满足起点的入度比出度小1和终点的出度比入度大1时,欧拉道路一定存在;

判断图的连通性有两种方法:1、利用并查集,只判断有几个根节点即可;2、使用DFS,做法实质上就是判断联通块的个数

利用并查集:

# include<iostream>
# include<cstdio>
# include<map>
# include<set>
# include<string>
# include<cstring>
# include<algorithm>
using namespace std;

int n,in[26],out[26],fa[26],mark[26];
char p[1005];

int fin(int u)
{
    int x=u;
    while(fa[u]!=u)
        u=fa[u];
    while(fa[x]!=u){
        int k=fa[x];
        fa[x]=u;
        x=k;
    }
    return u;
}

int get()
{
    int cnt=0;
    for(int i=0;i<26;++i)
        if(mark[i]&&fa[i]==i)
            ++cnt;
    return cnt;
}

bool judge()
{
    if(get()>1)
        return false;

    int cnt=0;
    for(int i=0;i<26;++i)
        if(mark[i]&&in[i]!=out[i])
            ++cnt;
    if(cnt>2)
        return false;
    if(cnt==0)
        return true;
    if(cnt==1)
        return false;

    int k1=0,k2=0;
    for(int i=0;i<26;++i){
        if(mark[i]&&in[i]!=out[i]){
            if(in[i]+1==out[i])
                k1=1;
            if(in[i]==out[i]+1)
                k2=1;
        }
    }
    return k1&&k2;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(mark,0,sizeof(mark));
        for(int i=0;i<26;++i)  fa[i]=i;
        scanf("%d",&n);
        for(int i=0;i<n;++i){
            scanf("%s",p);
            int l=strlen(p);
            mark[p[0]-'a']=mark[p[l-1]-'a']=1;
            ++out[p[0]-'a'];
            ++in[p[l-1]-'a'];
            int u=fin(p[0]-'a');
            int v=fin(p[l-1]-'a');
            if(u!=v)
                fa[u]=v;
        }
        if(judge())
            printf("Ordering is possible.
");
        else
            printf("The door cannot be opened.
");
    }
    return 0;
}

  

使用DFS:

# include<iostream>
# include<cstdio>
# include<map>
# include<set>
# include<string>
# include<cstring>
# include<algorithm>
using namespace std;

int n,in[26],out[26],mark[26],vis[26],mp[26][26];
char p[1005];

void dfs(int u)
{
    for(int i=0;i<26;++i){
        if(mark[i]&&!vis[i]&&mp[u][i]){
            vis[i]=1;
            dfs(i);
        }
    }
}

bool judge()
{
    int cnt=0;
    memset(vis,0,sizeof(vis));
    for(int i=0;i<26;++i){
        if(mark[i]&&!vis[i]){
            ++cnt;
            vis[i]=1;
            dfs(i);
        }
    }
    if(cnt>1)
        return false;

    for(int i=0;i<26;++i)
        if(mark[i]&&vis[i]==0)
            return false;

    cnt=0;
    for(int i=0;i<26;++i)
        if(mark[i]&&in[i]!=out[i])
            ++cnt;
    if(cnt>2)
        return false;
    if(cnt==0)
        return true;
    if(cnt==1)
        return false;

    int k1=0,k2=0;
    for(int i=0;i<26;++i){
        if(mark[i]&&in[i]!=out[i]){
            if(in[i]+1==out[i])
                k1=1;
            if(in[i]==out[i]+1)
                k2=1;
        }
    }
    return k1&&k2;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(in,0,sizeof(in));
        memset(mp,0,sizeof(mp));
        memset(out,0,sizeof(out));
        memset(mark,0,sizeof(mark));
        scanf("%d",&n);
        for(int i=0;i<n;++i){
            scanf("%s",p);
            int l=strlen(p);
            mp[p[0]-'a'][p[l-1]-'a']=mark[p[0]-'a']=mark[p[l-1]-'a']=1;
            ++out[p[0]-'a'];
            ++in[p[l-1]-'a'];
        }

        if(judge())
            printf("Ordering is possible.
");
        else
            printf("The door cannot be opened.
");
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/20143605--pcx/p/4857641.html