UVa 10129 - Play on Words(欧拉道路)

本文探讨如何利用欧拉道路算法解决将一系列单词首尾相连排序的问题,详细解释了算法的两个关键条件,并通过代码实例展示了解决方案。

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

给出n个单词, 是否可以把所有单词排成一个首尾相连的排序。


典型的欧拉道路的题, 把字母当成结点,然后判断是否为欧拉道路。


欧拉道路存在的两个条件:

1.最多只能有两个结点的入度不等于出度,两点有一点的入度 - 出度 = 1,此为起点, 另一点出度 - 入度 = 1, 此为终点。另外就是每个点的入度等于出度。

2.忽略方向得到的地图连通。


#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>

using namespace std;

const int maxn = 26 + 7;

struct Word{
    int in, out;
};

int k, n, cnt;
int G[maxn][maxn];
int visited[maxn];
Word word[maxn];

void init() {
    for(int i = 0; i < 26; ++i) {
        word[i].in = word[i].out = 0;
    }
}

bool dfs(int u, int k) {
    if(k == cnt) return true;
    for(int v = 0; v < 26; v++) {
        if (visited[v] == 1 && G[u][v]) {
            visited[v] = -1;
            return dfs(v, k + 1);
        }
    }
    return false;
}

int main() {
    int T, cnt_in, cnt_out;
    bool ok1, ok2, cannt;
    string t;
    cin >> T;
    while(T--) {
        cnt = cnt_in = cnt_out = 0;
        ok1 = ok2 = cannt = false;
        init();
        memset(G, 0, sizeof(G));
        memset(visited, 0, sizeof(visited));
        cin >> n;
        for(int i = 0; i < n; i++) {
            cin >> t;
            G[t[0] - 'a'][t[t.size() - 1] - 'a'] = G[t[t.size() - 1] - 'a'][t[0] - 'a'] = 1;
            if(!visited[t[0] - 'a']) cnt++;
            visited[t[0] - 'a'] = 1;
            if(!visited[t[t.size() - 1] - 'a']) cnt++;
            visited[t[t.size() - 1] - 'a'] = 1;
            ++word[t[0] - 'a'].in;
            ++word[t[t.size() - 1] - 'a'].out;
        }


        for(int i = 0; i < 26; i++) {
            if(word[i].in - word[i].out > 1) cannt = true;
            else if(word[i].in - word[i].out < -1) cannt = true;
            if(word[i].in - word[i].out == 1) ++cnt_in;
            else if(word[i].in - word[i].out == -1) ++cnt_out;
        }

        if(!cannt)
            if((cnt_in == 1 && cnt_out == 1) ||
               (cnt_in == 0 && cnt_out == 0)) ok1 = true;

        if(ok1 && !cannt) {
            for(int i = 0; i < 26; i++) {
                if(visited[i] == 1) {
                    visited[i] = -1;
                    ok2 = dfs(i, 1);
                    break;
                }
            }
        }

        if(ok1 && ok2 && !cannt) cout << "Ordering is possible." << endl;
        else cout << "The door cannot be opened." << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值