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.\n");
        else
            printf("The door cannot be opened.\n");
    }
    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.\n");
        else
            printf("The door cannot be opened.\n");
    }
    return 0;
}

  

时间: 2024-10-08 10:22:15

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

UVA 10129 Play on Words(欧拉道路)

题意:给你n个字符串,问你是否可以出现一条链,保证链中每个字符串的第一个元素与上一个字符串的最后一个元素相同,注意可能重复出现同一个字符串 题解:以每一个字符串第一个元素指向最后一个元素形成一个有向图,判断这个有向图是否可以形成欧拉路就好 注意可能有重边与自环,因此求欧拉路时判断的是是否使用完了所有的边,求起点时注意出度与入度的计算 欧拉道路是从一个点一笔画完整张图(欧拉回路保证回到起点),注意除了起点与终点以外所有的点出度入度相等 起点出度大入度1,终点相反(所有的点出入度相等也可以),根据这

UVa 10129 Play On Words【欧拉道路 并查集 】

题意:给出n个单词,问这n个单词能否首尾接龙,即能否构成欧拉道路 按照紫书上的思路:用并查集来做,取每一个单词的第一个字母,和最后一个字母进行并查集的操作 但这道题目是欧拉道路(下面摘自http://blog.csdn.net/hcbbt/article/details/9316301) 关于欧拉道路(from Titanium大神): 判断有向图是否有欧拉路 1.判断有向图的基图(即有向图转化为无向图)连通性,用简单的DFS即可.如果图都不连通,一定不存在欧拉路 2.在条件1的基础上   对于

POJ--1300--Door Man【判断欧拉通路】

链接:http://poj.org/problem?id=1300 题意:有n个房间,每个房间有若干个门和别的房间相连,管家从m房间开始走,要回到自己的住处(0),问是否有一条路可以走遍所有的门并且没有重复的路. 思路:判断是否存在欧拉通路,根据欧拉通路.欧拉回路的性质来做.有两种情况:一种是欧拉回路,所有房间的门的个数都是偶数个,并且此时初始房间不是0,此时存在要求的路径,如果初始是0则不行.另一种是欧拉通路,只有两个房间门是奇数个,剩下都是偶数个,并且这两个房间一个是0,一个是当前起点,并且

UVA 10441 - Catenyms(欧拉道路)

UVA 10441 - Catenyms 题目链接 题意:给定一些单词,求拼接起来,字典序最小的,注意这里的字典序为一个个单词比过去,并非一个个字母 思路:欧拉回路.利用并查集判联通,然后欧拉道路判定,最后dfs输出路径 代码: #include <cstdio> #include <cstring> #include <string> #include <vector> #include <iostream> #include <algo

【UVa】12118 Inspector&#39;s Dilemma(欧拉道路)

题目 题目 ? ? 分析 很巧秒的一道题目,对着绿书瞎yy一会. 联一下必须要走的几条边,然后会形成几个联通分量,统计里面度数为奇数的点,最后再减去2再除以2.这样不断相加的和加上e再乘以t就是答案, 为什么呢?题目要求最短距离,那么必定是欧拉道路,那么为了构造出最短欧拉道路,要将奇度数的点减小至2个,然而各个道路不一定联通,还需要计算一下联通块数量n,结果加上n-1后,再乘t,因为需要n-1条边将各个联通块连接起来. 注意题目已保证每两个点都有路,所以上面才能那么肆无忌惮的连边. ? ? 代码

无向图与有向图判定欧拉道路与欧拉回路的方法

欧拉道路: 从无向图中的一个节点出发走一条道路,每条边恰好经过一次,这样的线路成为欧拉道路. 下面给出欧拉道路的判定方法: 有向图: 图必须是连通的,而且最多只能有两个点入度不等于出度,而且这两个点其中一个点的入度+1=出度,另一个点的出度+1=入度,如果有的点出度!=入度&&出度与入度的绝对值差还不等于1,则这个图不是欧拉道路. 无向图: 图必须是连通的,而且最多有两个奇度点,则是欧拉道路. 判定图连通的方法: 无向图用dfs访问,看看点是否全部被访问. 有向图先转化为无向图,然后再用d

POJ 2513 Colored Sticks(欧拉道路+字典树+并查集)

http://poj.org/problem?id=2513 题意: 给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的. 思路: 题目很明显的是欧拉道路的问题. 欧拉道路的关键是: ①图是连通的. ②最多只能有两个奇点.(不能只存在一个奇点) 本来是想用map映射的,但是太多了,比较费时,这里用字典树的话会比较省时,判断图是否连通可以用并查集来完成. 1 #include<iostream> 2 #include<algori

Nyoj42 一笔画问题 (欧拉道路)

http://acm.nyist.net/JudgeOnline/problem.php?pid=42题目链接 #include <cstdio> #include <cstring> #define CLR(arr) memset(arr,0,sizeof(arr)) #define P 1001 int G[P],fa[P]; int find(int x){return x==fa[x]?x:x=find(fa[x]);} int main() {     int n,a,b

dfs求欧拉道路

从一个节点出发的一条路径每条边只经过一次,则把这条路称作欧拉道路. 欧拉道路存在着这样的性质除起点和终点以外所有经过的节点的出度和入度相等,也就是说除起点和终点以外的节点的度都为偶数. 同时一个无向图是连通的,且最多存在两个奇点,则一定存在欧拉道路,并且如果是有两个奇点,欧拉道路一定是从一个奇点出发到达另外一个奇点,如果没有奇点,则从任何一个节点出发然后最终回到该点(欧拉回路),奇点为一的情况是不存在的. 对于存在欧拉道路的情况,最多只能有两个点的入度不等于出度,而且必须是其中一个节点的入度比出