Play on Words,UVA 10129——求欧拉回路/欧拉通路

Play on words

紫书上的一道题:

输入n(n<=100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同。每个单词最多包含1000个小写字母。输入中可以有重复单词。

分析:

把字母看成结点,单词看成有向边,则问题有解,当且仅当图中存在欧拉通路/欧拉回路

欧拉通路/回路:通过图中所有边一次且仅一次行遍所有顶点的通路/回路

有向图存在欧拉回路的判断条件:当且仅当有向图是强连通的,且没有奇度顶点,所有顶点的入度等于出度

有向图存在欧拉通路的判断条件:当且仅当有向图是单向连通的,且恰有两个奇度顶点,一个顶点的入度比出度大一,另一个顶点的出度比入度大一,其余顶点的入度等于出度

判断连通性,dfs,bfs,Union-Find Set

注:百度上用dfs写的代码都过不了这个样例:

1

3

dc

cb

ba

因为除非是欧拉回路才可以任意的起点,如果存在奇度顶点,就必须以两个奇度顶点为起点和终点

如下附上百度到的代码,最后面附上用并查集写的ac的代码

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
using namespace std;
int Map[26][26];
int in[26],out[26];
bool vis[26];
int T,N;
void dfs(int k)
{
    vis[k]=true;
    for(int i=0;i<26;i++)
    {
        if(Map[k][i]&&!vis[i])
            dfs(i);
    }
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        char C[1100];
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(Map,0,sizeof(Map));
        for(int i=0;i<N;i++)
        {
            scanf("%s",C);
            int len=strlen(C);
            ++Map[C[0]-'a'][C[len-1]-'a'];
            ++out[C[0]-'a'];
            ++in[C[len-1]-'a'];
        }
        int a=0,b=0;
        bool flag=true;
        for(int i=0;i<26;i++)
        {
            if(in[i]!=out[i])
            {
                if(in[i]==out[i]+1) a++;
                else if(in[i]+1==out[i]) b++;
                else {flag=false;break;}
            }
        }
        if(a&&b&&a+b>2)  flag=false;
        if(flag)
        {
            memset(vis,false,sizeof(vis));
            for(int i=0;i<26;i++)
            if(out[i]) {dfs(i);break;}
            bool flag1=true;
            for(int i=0;i<26;i++)
            {
                if(out[i]&&!vis[i]) {flag1=false;break;}
                if(in[i]&&!vis[i]) {flag1=false;break;}
            }
            if(flag1)
            {
                cout<<"Ordering is possible.\n";
            }
            else {cout<<"The door cannot be opened.\n";}
        }
        else {
            cout<<"The door cannot be opened.\n";
        }

    }
    return 0;
}

并查集:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=a;i<b;++i)
#define mes(s,c) memset(s,c,sizeof(s))
using namespace std;
int in[26],ou[26];
char str[1010];
int fa[26];
int n;
void Init()
{
    mes(in,0),mes(ou,0);
    FOR(i,0,26){
        fa[i]=i;
    }
}
int Find(int x)
{
    return fa[x]==x ? x:fa[x]=Find(fa[x]);
}
bool check_degree()
{
    int num1=0,num2=0;
    for(int i=0;i<26;++i){
        if(in[i]!=ou[i]){
            if(in[i]==ou[i]+1) num1++;
            else if(in[i]+1==ou[i]) num2++;
            else return false;
        }
    }
    if(num1&&num2&&num1+num2>2) return false;
    return true;
}
bool check_connected()
{
    int cnt=0;
    FOR(i,0,26){
        if( (in[i]||ou[i])&&fa[i]==i){
            ++cnt;
        }
    }
//    cout<<"cnt="<<cnt<<endl;
    if(cnt!=1) return false;
    return true;
}
void solve()
{
    if(check_degree()){
        if(check_connected())
            printf("Ordering is possible.\n");
        else
            printf("The door cannot be opened.\n");
    }
    else{
        printf("The door cannot be opened.\n");
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--){
        Init();
        scanf("%d",&n);
        REP(i,n){
            scanf("%s",str);
            int l=strlen(str);
            int x=str[0]-'a';
            int y=str[l-1]-'a';
            in[y]++;
            ou[x]++;
            fa[Find(x)]=Find(y);
        }
        solve();
    }
    return 0;
}
时间: 2024-11-13 08:07:24

Play on Words,UVA 10129——求欧拉回路/欧拉通路的相关文章

UVA 10129-Play on Words(欧拉通路)

题意:给N个单词,判断是否单词首尾(前一个单词的尾字符与后一个单词的头字符相同)相连能否形成一条链. 解析:找欧拉通路(欧拉回路或是欧拉链路),但这题事先需要并查集一下,判断是否只属于一个集合,如aa,bb,cc不能形成一条链,但会判断成欧拉回路. 代码如下: #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<set> #include

UVA 10129 Play on Words (欧拉通路)

题意: 输入N(N <= 100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同(例如:acm,malform,mouse).每个单词最多包含 1000 个小写字母.输入中可以有重复的单词. 思路: 把一个字母的两端开成节点,单词看成有向边,若问题有借,当且仅当图中存在欧拉通路.所有只需要判断由单词而构建的图是否存在欧拉通路,由于是有向边,所以利用有向图欧拉通路的判定就可以了. 判定条件 (1):底图是连通图 (2):可以有两个奇点,其中

uva 11317 - GCD+LCM(欧拉函数+log)

题目链接:uva 11317 - GCD+LCM 题目大意:给定n,求出1~n里面两两的最大公约的积GCD和最小公倍数的积LCM,在10100进制下的位数. 解题思路:在n的情况下,对于最大公约数为i的情况又phi[n/i]次.求LCM就用两两乘积除以GCD即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; ty

UVA 11440 - Help Tomisu(欧拉函数)

UVA 11440 - Help Tomisu 题目链接 题意:给定n和m,求[2,n!]中,所有质因子个数都大于m的个数 思路:?(m!)表示小于m!并与m!互质的个数,而与m!互质的个数,他的质因子肯定不包含1-m,因此就是满足条件的.然后对于这题而言,则是要求n!中,不与m!互质的个数,答案取模100000007 那么先看一个证明: 求kn中与n互质的个数,答案为k?(n). ?(n)表示1-n中与n互质的个数,那么由此考虑[n + 1, 2n], [2n + 1, 3n]...这每个区间

√n求单值欧拉函数

基本定理: 首先看一下核心代码: 核心代码 原理解析: 当初我看不懂这段代码,主要有这么几个问题: 1.定理里面不是一开始写了一个n*xxx么?为什么代码里没有*n? 2.ans不是*(prime[i]-1)么?为什么到了第二个while循环变成*prime[i]了? 3.定理里面不是要/pi么?为什么代码里没有/pi????????????? 公式化简 首先我们来分析一下整个程序的原理,如果把程序的原理搞明白了,这三个问题也就自然而然的解决了 这个程序的原理是基于唯一分解定理: 那么我们可以把

uva 10054 The Necklace(欧拉通路)

提交了7次,总算AC了.题目不难,就是判断下欧拉通路.注意细节. /* Status:AC Title :The Necklace */ #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <string> #include <stack> #include <queue> #include <s

POJ--1300--Door Man【推断无向图欧拉通路】

链接:http://poj.org/problem?id=1300 题意:有n个房间.每一个房间有若干个门和别的房间相连.管家从m房间開始走.要回到自己的住处(0),问是否有一条路能够走遍全部的门而且没有反复的路. 无向图欧拉通路充要条件:G为连通图,而且G仅有两个奇度结点(度数为奇数的顶点)或者无奇度结点. 无向图欧拉回路充要条件:G为无奇度结点的连通图. 思路:推断是否存在欧拉通路.依据欧拉通路.欧拉回路的性质来做.有两种情况:一种是欧拉回路.全部房间的门的个数都是偶数个,而且此时初始房间不

POJ 2337 Catenyms (有向图欧拉通路)

Catenyms Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9914   Accepted: 2588 Description A catenym is a pair of words separated by a period such that the last letter of the first word is the same as the last letter of the second. For e

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

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