UVaOJ 10129 - Play on Words

——by A Code Rabbit


Description

输入一些单词,要求把这些所有的单词都用成语接龙的办法连起来。
输出可能或者不可能。


Types

Date Structure :: Graphs


Analysis

对于每个单词,有价值的就是第一个单词和最后一个单词。

虽然输入数据可能高达100000个,但是字母只有26个。

可以以这些字母为点,把这题的模型化为有向图。

然后题目所求的就是这无向图的一个欧拉路径。

要求欧拉路径,可以计算每个点的入度和出度,容易理解除了第一个单词开头的字母,和最后一个单词结尾的字母,其他的字母入度和出度必然相等。

而第一个单词开头的字母和最后一个单词结尾的字母,前者入度比出度大一,后者出度比入度小一。

不过要记得,当所有点的入度和出度都相等,即构成欧拉回路,也符合题目的要求。

最后别忘了这个定理成立的条件——这个图的无向图,必须是连通的。

DFS 一下某个点的连同分支是否可以到达每个点即可。


Solution

// UVaOJ 10129
// Play on Words
// by A Code Rabbit

#include <cstdio>
#include <cstring>

const int LIMITS = 2000;

int t;

char word[LIMITS];
int n;

bool graph[30][30];
bool is_existing[30];
int difference[30]; // It means the in_order minus the out_order.

bool is_visited[30];

void Process(char* word);
bool MatchCondition();
int Search(int pos);

int main() {
    scanf("%d", &t);
    while (t--) {
        // INIT.
        memset(difference, 0, sizeof(difference));
        memset(graph, false, sizeof(graph));
        memset(is_existing, false, sizeof(is_existing));
        memset(is_visited, false, sizeof(is_visited));
        // Inputs and count.
        scanf("%d", &n);
        getchar();
        while (n--) {
            gets(word);
            // Processing string.
            Process(word);
        }
        // Compete the number of letters.
        int num_letters = 0;
        for (int i = 0; i < 26; ++i) {
            if (is_existing[i]) {
                ++num_letters;
            }
        }
        // Judge whether in_order and out_order match condition.
        bool can_order = MatchCondition();   
        // Judge whether the graph without direction is a connected graph.
        if (can_order) {
            for (int i = 0; i < 26; ++i) {
                if (is_existing[i]) {
                    if (num_letters != Search(i)) {
                        can_order = false;
                    }
                    break;
                }
            }
        }
        // Outputs.
        printf("%s\n", can_order ? "Ordering is possible." : "The door cannot be opened.");
    }

    return 0;
}

void Process(char *word) {
    int first = word[0] - 'a';
    int last = word[strlen(word) - 1] - 'a';
    ++difference[first];
    --difference[last];
    graph[first][last] = true;
    graph[last][first] = true;
    is_existing[first] = true;
    is_existing[last] = true;
}

bool MatchCondition() {
    int num_nonzero = 0;
    int num[26];
    for (int i = 0; i < 26; ++i) {
        if (difference[i]) {
            num[num_nonzero++] = difference[i];
        }
    }
    if (num_nonzero == 0) {
        return true;
    }
    if (num_nonzero != 2) {
        return false;
    }
    if ((num[0] == -1 && num[1] ==  1) || 
        (num[0] ==  1 && num[1] == -1))
    {
        return true;
    } else {
        return false;
    }
}

int Search(int pos) {
    if (is_visited[pos]) {
        return 0;
    }
    is_visited[pos] = true;
    int sum = 1;
    for (int i = 0; i < 26; ++i) {
        if (graph[pos][i]) {
            sum += Search(i);
        }
    }
    return sum;
}


下载PDF

参考资料:无

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值