欧拉路径:单词游戏

此博客主要探讨了如何利用并查集判断一个由26个字母组成的图是否存在欧拉路径。通过分析每个字母的入度和出度,以及整个图的联通性,来确定单词是否能按照特定顺序排列。程序实现包括初始化并查集,统计字母的入出度,检查起点和终点的唯一性,以及验证所有边是否连通。
摘要由CSDN通过智能技术生成

原题链接:https://www.acwing.com/problem/content/1187/
在这里插入图片描述
在这里插入图片描述

/*
    26个字母之间建立边,单词作为边
    只需要判断两点:
    
    图是否联通,这个可以使用并查集,只要是被这个单词连过就加到把首位
    字母加到一个集合中
    
    除了起点和终点以外,其他点的入度等于出度。
    首先需要找到起点和终点。起点的出度=入度+1,并且仅有一个起点
    终点的入度=出度+1,并且只有一个。
    其他点的入度等于出度。
    
    以上两个条件任意一个不满足,都不成立。
*/

#include <iostream>
#include <cstring>

using namespace std;

const int N = 30;  // 点数最多26个

int n;  // 单词数目,图中对应边数
int p[N];  // 并查集
int din[N], dout[N];
bool st[N];  // 记录某个字母是否作为单词首尾出现过

int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main() {

    char str[1010];

    int T;
    scanf("%d", &T);
    while (T--) {

        cin >> n;

        memset(din, 0, sizeof din);
        memset(dout, 0, sizeof dout);
        memset(st, 0, sizeof st);
        for (int i = 0; i < 26; i++) p[i] = i;

        for (int i = 0; i < n; i++) {
            scanf("%s", str);
            int a = str[0] - 'a', b = str[strlen(str) - 1] - 'a';
            st[a] = st[b] = true;
            // a的出度加一。b的入度加一
            dout[a]++, din[b]++;
            // 合并
            p[find(a)] = find(b);
        }

        // 判断度数是否正确
        int start = 0, end = 0;
        bool success = true;  // 是否存在欧拉路径
        for (int i = 0; i < 26; i++) 
            if (din[i] != dout[i]) {
                if (din[i] == dout[i] + 1) end++;  // 终点数目,只能有1个
                else if (dout[i] == din[i] + 1) start++;  // 起点数目,只能有一个
                else {
                    success = false;
                    break;
                }
            }
            
        // 判断起点终点数目是否正确
        if (success && !(!start && !end || start == 1 && end == 1)) success = false;

        // 判断所有边是否连通
        int rep = -1;  // 代表元素
        for (int i = 0; i < 26; i++)
            if (st[i]) {  // 说明该字母在单词中出现过,所有st为true的都应该在一个集合中
                if (rep == -1) rep = find(i);
                else if (rep != find(i)) {  // 说明存在边不连通
                    success = false;
                    break;
                }
            }

        if (success) puts("Ordering is possible.");
        else puts("The door cannot be opened.");
    }

    return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值