[NOIP2000 提高组] 单词接龙 C++

[NOIP2000 提高组] 单词接龙

题目链接

点击此处前往该题目

提示

由于题目比较古老,所以题目中的部分表述不清楚甚至存在误导的现象。以下是我参考了各神犇的题解之后,自己对题目的理解,如有错误或者疏漏之处还请指正。

  • 单词相连,是根据最小重叠部分来进行连接的,即使单词间存在包含的现象,也有可能相连,比如,asaasaasa ,是直接在 a 处相连的,结果应该是 asasaasa ,在该题中,这样的两个词并不是 “包含” 关系,注意“包含”时应判定为 false
  • 每个单词最多只能用两次。
  • 题目说的是相邻部分不能“包含”,所以龙头的部分也有可能“包含”尾巴。不过我写的时候没注意这个好像也AC了

解题思路

如果上述都理解了,而且你对深搜和广搜有一定的基础,那么这道题的思路就已经很清晰了,就是使用DFS对所有可能的情况进行列举,最后输出最长单词的长度。唯一需要注意的点就是判断两个单词的重叠部分并将它们合并,这也是这道题的难点。

代码的书写

我们首先需要定义需要用到的变量,个人的习惯如下:

#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 25;
string strs[maxn]; // 用于储存输入的单词
int cnt[maxn]; // 用于判断每个单词的使用次数
int n, ans = 0; // 这里定义为全局变量,实际根据个人代码习惯而定

接下来就需要给出判断单词重叠部分的函数了

// 这里传入的是引用,因为我直接将单词在函数内进行了合并
bool Check(int idx, string &now)
{
    int len1 = now.length();
    int len2 = strs[idx].length();
    int i, j;
    /* 从龙头的最末尾开始,注意退出条件,当i==0时,若其中的if条件句成立,
    那么就说明尾巴包含龙头;若不成立,那么还是没找到匹配项,两者的结果都是false */
    for(i = len1 - 1; i > 0; ) 
    {
        if(now[i] == strs[idx][0]) // 匹配到相同的字母
        {
        	/* 注意在逐字匹配时不要让i越界,同时如果j==len2-1,同理,
        	龙头也有可能包含尾巴,但是注意不能直接在for循环的条件里跳出,
        	不然会返回true导致后面出错 */
            for(j = 0; j < len2 && i <= len1 - 1; j++)
            {
                if(j >= len2 - 1 || now[i++] != strs[idx][j])
                    return false;
            }
            now = now + strs[idx].substr(j); // 合并
            return true;
        }
        else
            i--; // 没匹配到就往前走
    }
    return false; 
}

接下来是DFS的部分

bool IsOver(string now) // 判断还有没有可以合并的单词
{
    for(int i = 0; i < n; i++)
    {
        if(cnt[i] < 2 && Check(i, now))
            return false;
    }
    return true;
}

void DFS(string now)
{
    if(IsOver(now))
    {
        int len = now.length();
        // cout << now << endl;
        ans = ans > len ? ans : len;
        return;
    }
    for(int i = 0; i < n; i++)
    {
        string tmp = now;
        if(cnt[i] >= 2 || !Check(i, now)) continue;
        cnt[i]++;
        DFS(now);
        cnt[i]--; // 回溯
        now = tmp;
    }
}

最后是main函数中的输入部分

int main()
{
    char ch;
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> strs[i];
    cin >> ch;
    for(int i = 0; i < n; i++)
        if(strs[i][0] == ch) // 注意处理使用次数
        {
            cnt[i]++;
            DFS(strs[i]);
            cnt[i]--;
        }
    cout << ans << endl;
    return 0;
}

完整代码

最后,这是完整的代码

#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 25;
string strs[maxn];
int cnt[maxn];
int n, ans = 0;

bool Check(int idx, string &now)
{
    int len1 = now.length();
    int len2 = strs[idx].length();
    int i, j;
    for(i = len1 - 1; i > 0; )
    {
        if(now[i] == strs[idx][0])
        {
            for(j = 0; j < len2 && i <= len1 - 1; j++)
            {
                if(j >= len2 - 1 || now[i++] != strs[idx][j])
                    return false;
            }
            now = now + strs[idx].substr(j);
            return true;
        }
        else
            i--;
    }
    return false;
}

bool IsOver(string now)
{
    for(int i = 0; i < n; i++)
    {
        if(cnt[i] < 2 && Check(i, now))
            return false;
    }
    return true;
}

void DFS(string now)
{
    if(IsOver(now))
    {
        int len = now.length();
        // cout << now << endl;
        ans = ans > len ? ans : len;
        return;
    }
    for(int i = 0; i < n; i++)
    {
        string tmp = now;
        if(cnt[i] >= 2 || !Check(i, now)) continue;
        cnt[i]++;
        DFS(now);
        cnt[i]--;
        now = tmp;
    }
}

int main()
{
    char ch;
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> strs[i];
    cin >> ch;
    for(int i = 0; i < n; i++)
        if(strs[i][0] == ch)
        {
            cnt[i]++;
            DFS(strs[i]);
            cnt[i]--;
        }
    cout << ans << endl;
    return 0;
}
  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单词是一种游戏,玩家需要在给定的单词列表中,按照首尾字母匹配的顺序依次连单词,直到无法继续连为止。在C语言中,我们可以通过使用字符串和循环等基本概念来实现单词。 首先,我们需要定义一个单词列表,可以使用字符数组或字符串数组来存储。例如,可以使用以下代码定义一个含有5个单词的字符串数组: ```c char words[5][10] = { "apple", "elephant", "tent", "tiger", "rat" }; ``` 然后,我们可以编写一个函数来实现单词的逻辑。该函数将受一个单词列表作为参数,并依次连匹配的单词。 ```c #include <stdio.h> #include <string.h> void wordChain(char words[][10], int numWords) { char currentWord[10]; int i, j; int chainLength = 0; // 长度 // 遍历单词列表 for (i = 0; i < numWords; i++) { strcpy(currentWord, words[i]); // 复制当前单词作为的起点 chainLength = 1; // 长度初始化为1 // 在单词列表中搜索下一个匹配的单词 for (j = 0; j < numWords; j++) { // 单词的首字母和之前的单词的尾字母相同,且未被使用过 if (currentWord[strlen(currentWord) - 1] == words[j][0] && strcmp(currentWord, words[j]) != 0) { printf("%s -> ", currentWord); strcpy(currentWord, words[j]); chainLength++; // 长度增加 if (chainLength == numWords) { // 如果长度等于单词总数,则完成 printf("%s\n", currentWord); return; } j = -1; // 从头开始搜索下一个匹配的单词 } } } // 无法继续 printf("无法!\n"); } int main() { char words[5][10] = { "apple", "elephant", "tent", "tiger", "rat" }; wordChain(words, 5); return 0; } ``` 上述代码中,我们定义了一个`wordChain`函数来实现单词逻辑。该函数遍历单词列表,并通过比较首尾字母来匹配单词。如果找到匹配的单词,则将其设置为当前单词,继续搜索下一个匹配的单词。如果完成(长度等于单词总数),则输出结果;如果无法继续,则输出提示。 在`main`函数中,我们定义了一个字符串数组`words`,并调用`wordChain`函数来进行单词。最终程序将输出如下结果: ``` apple -> elephant -> tent -> tiger -> rat ``` 这就是一个基于C语言实现的简单单词游戏。实际上,我们可以根据需求进行更复杂的单词逻辑设计,增加限制条件或规则,使游戏更加有趣和挑战。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值