UVA 10129 Play on Words(欧拉回路)

本文介绍了一种使用无向图和并查集解决单词排列问题的方法,通过判断图中是否存在欧拉回路来确定单词序列是否合法,并提供了两种实现方式:并查集和深度优先搜索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Question:题目详情(http://vjudge.net/contest/133965#problem/C)
题目大意:有很多单词,要你把他们排列成一个单词的末尾为下一个单词的首字母,问这么排列是否可行
解题思路:根据题意建立一个无向图(一个单词的首尾字母关系),判断图中是否存在欧拉回路,判断欧拉路径的方法两个因素:1。图必须连通(并查集,dfs可执行),2。出入度数必须满足每个节点的入度和出度相等(有可能除去除开始,结尾),开始节点(入度+1==出度),末尾节点(入度=出度+1),开始末尾节点可能存在(有可能又回到了初始节点),存在也只能各存在一个

//并查集解法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
const int maxn=30;
char s[1005];
int fa[maxn],g[maxn][maxn],in[maxn],out[maxn],flag;
int findx(int x){  //找其父节点
    if(fa[x]!=x)
        return fa[x]=findx(fa[x]);
    else return x;
}
void Union(int x,int y){   //将两个节点关联
    int t1=findx(x),t2=findx(y);
    if(t1!=t2)
        fa[t1]=t2;
}
bool judge(){   //判断是否存在欧拉路径:每个节点的入度和出度相等(有可能除去除开始,结尾),开始节点(入度+1==出度),末尾节点(入度=出度+1),开始末尾节点可能存在(有可能又回到了初始节点)
    bool Star=false ,End=false;
    for(int i=0;i<maxn;i++){
        if(in[i]!=out[i]){
            if(in[i]+1==out[i]&&!Star)
                Star=true;
            else if(in[i]==out[i]+1&&!End)
                End=true;
            else return false ;
        }
    }
    return true;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        scanf("%d",&n);
        memset(g,0,sizeof(g));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=0;i<maxn;i++)
            fa[i]=i;
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int u=s[0]-'a',v=s[strlen(s)-1]-'a';
            in[v]++;   //每个节点的入度
            out[u]++;    //每个节点的出度
            Union(u,v);
        }
        if(judge()){
            flag=0;
            for(int i=0;i<maxn;i++){
                if(in[i]+out[i])
                    if(fa[i]==i)
                       flag++;   
            }
            if(flag>1)   //如果只有一个父节点,则说明给出的图是连通的 
                printf("The door cannot be opened.\n");
            else printf("Ordering is possible.\n");
        }
        else printf("The door cannot be opened.\n");
    }
    return 0;
}
//DFS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
#define maxn 30
char s[1005];
int g[maxn][maxn],vis[maxn],in[maxn],out[maxn],star;
void dfs(int);
bool okdfs();
bool judge();
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        memset(vis,0,sizeof(vis));
        memset(g,0,sizeof(g));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=0;i<n;i++){
            cin>>s;
            int u=s[0]-'a',v=s[strlen(s)-1]-'a';
            in[v]++;
            out[u]++;
            g[u][v]++;  //根据一个单词的首字母和尾字母关系,建图
            g[v][u]++;
            star=u;
        }
        dfs(star);   //从任意节点开始访问节点
        if(judge()&&okdfs())
            printf("Ordering is possible.\n");
        else printf("The door cannot be opened.\n");
    }
    return 0;
}
void dfs(int u)   //用dfs访问所有的节点
{
    vis[u]=1;
    for(int i=0;i<maxn;i++){
        if(g[u][i]>0){
            g[u][i]--;
            g[i][u]--;
            dfs(i);
        }
    }
}
bool okdfs()  //判断是否节点是否都被访问到了
{
    for(int i=0;i<maxn;i++){
        if(in[i]+out[i])    //有些点可能给出的数据没有(因为有26个字母)
            if(!vis[i])
                return false;
    }
    return true;
}
bool judge()   //判断是否度数满足欧拉路径
{
    bool Star=false,End=false;
    for(int i=0;i<maxn;i++){
        if(in[i]!=out[i]){
            if(in[i]+1==out[i]&&!Star)  //只有一个起始节点
               Star=true;
        else if(in[i]==out[i]+1&&!End) //只有一个末尾节点
            End=true;
        else return false;
        }
    }
    return true;
}

体会:并查集很简单,但自己的dfs很容易出问题,还得多练欧拉回路,dfs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值