信息学奥赛一本通 1220:单词接龙 | 1913:【00NOIP普及组】单词接龙 | OpenJudge NOI 2.5 8783 | 洛谷 P1019 [NOIP2000 提高组] 单词接龙

【题目链接】

ybt 1220:单词接龙
ybt 1913:【00NOIP普及组】单词接龙
OpenJudge NOI 2.5 8783:单词接龙
洛谷 P1019 [NOIP2000 提高组] 单词接龙

【题目考点】

  1. 字符串处理,二维数组存储多个字符串
  2. 深搜

【解题思路】

解法1:使用二维数组,构造接合点数组

(本解法有助于更细致地理解本题,但代码较长,思路理解后,可以转看解法2)
本题中“第几个”都是从0开始数的

1. 接合点概念

两个单词接合点为k的概念为:若两个单词可以接龙,接龙后第1个单词的第k位置和第二个单词的第0位置重合,那么称两单词的接合点为k。
若两单词不能接龙,接合点为0。
在这里插入图片描述

2. 最大接合点

两个单词可能会有多个接合点,由于本题要求的是最长的龙,两个单词接龙的重合部分越少,选择的接合点越大,最后得到的龙越长。因此本程序采用两个单词所有接合点中最大的接合点。

示例:
baa与aab接龙
可能的接龙为baab
baa
  aab
接合点为1
若接龙后为baaab
baa
    aab
接合点为2
这种情况的接合点的值更大,两单词的最大接合点为2

3. 相关数量关系

假设第一个单词长度为n1,第二个单词长度为n2,接合点为cp

  1. 接合部分长度为n1-cp
  2. 第二个单词接龙后使龙增加的长度为n2-n1+cp
  3. 接合部分长度若大于等于第二个单词的长度,那么第一个单词包含了第二个单词,二者不再是接龙关系。所以有结合部分长度要小于第二个单词的长度,即n1 - cp < n2
  4. 若接合点为0,则第二个单词包含了第一个单词,所以接合点要大于0,即cp > 0。(因此可以将不能接龙的情况设为cp = 0。)

4. 解题步骤

设二维数组cp,cp[i][j] 表示第i单词与第j单词的最大接合点。若i,j无法接龙,那么cp[i][j] = 0
设接龙数组lg, lg[i]表示龙中第i个单词的编号。

  • 第一步,求出任意两个单词间的接合点,构造cp数组

  • 第二步,在所有单词中找以初始字符开头的单词加入龙中,接下来不断搜索可以将哪些单词接在龙的后面。

  • 搜索过程:
    遍历所有单词,找能与当前龙中最后一个单词接龙的单词。
    找的过程中判断单词使用次数不超过2。
    每有一个新的单词成功接龙,则尝试更新最大接龙长度,而后继续搜索。
    搜索后状态还原。

5. 所谓的“包含关系”

题中“相邻的两部分不能存在包含关系”这句实在含混不清,让我一开始误以为两个词不能存在包含关系。其实是说某个词和两词的重合部分不能有包含关系。

例:
baba与bab,虽然baba包含bab,但二者之间是可以接龙的,结果是babab, 接龙方法为
baba
    bab

因此自己和自己也是有可能接龙的,如:
bab与bab,接成babab
bab
    bab

解法2:使用string类,每次循环寻找重合部分

思路与上一种方法基本一致,用string类写语意更直接,更易理解。
由于每次循环都要寻找重合部分,相比于上一种解法中将接合点预先都算出来,复杂度要更高一些。不过本题数据量很小,这点增加的复杂度可以接受。
与上方法取“最大接合点”同样道理,两单词重合部分越少,得到的龙越长。所以重合部分长度从小向大遍历,只要找到一次有重合部分,就不再寻找。
具体请看注释。

【题解代码】

解法1:使用二维数组,构造接合点数组
#include<bits/stdc++.h>
using namespace std;
#define N 25
char word[N][N];//word[i]:第i个单词
int cp[N][N];//最大接合点数组,cp[i][j]表示第i单词与第j单词的最大接合点
int len[N];//len[i]:第i个单词的长度
int exist[N];//exist[i]:第i个单词已经在龙中出现几次
char sc;//初始字符
int n;//单词数量
int lgLen, mxLgLen;//lgLen:当前龙长度 mxLgLen:最大的龙长度
//获取单词s1和单词s2的接合点,n1,n2是字符串s1,s2的长度
int getCatchPoint(char s1[], int n1, char s2[], int n2)
{//p:第s1单词的下标,判断第p位置是不是接合点。从后向前遍历,第一个找到的接合点就是最大接合点。
    for(int p = n1 - 1; p > 0 && n1 - p < n2 ; p--)//p > 0见题解思路3.4, n1 - p < n2见题解思路3.3
    {
        if(s1[p] == s2[0])//有相同的字符,二者可能接龙
        {
            bool isOk = true;//能否接龙
            for(int i = p + 1, j = 1; i < n1; ++i, ++j)//i是s1的下标,j是s2的下标,从接合点后一个位置开始遍历。
            {//判断s1从s[p]末尾是否与s2前一段字符相同 
                if(s1[i] != s2[j])//遇到不同的字符,无法接龙
                {
                    isOk = false;
                    break;
                }
            }
            if(isOk)
                return p;//返回接合点
        }
    }
    return 0;//没找到接合点,两单词没有接龙,返回0
}
//初始化cp数组
void initCp()
{
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j)
            cp[i][j] = getCatchPoint(word[i], len[i], word[j], len[j]);//看word[i]和word[j]能否接龙,并寻找接合点。
 }
//向龙中添加单词
void addWordToLg(int lw)//lw:龙中最后一个单词的编号
{
    if(lgLen > mxLgLen)//取最大值。必须放在这里,不能放在下面循环内。否则只有1个单词时,无法取到最大值。
        mxLgLen = lgLen;
    for(int i = 0; i < n; ++i)//遍历各个单词,看第i单词能否添加到龙中
    {
        if(cp[lw][i] > 0 && exist[i] < 2)//如果龙中最后一个单词后面可以接第i单词 且 该单词没有在龙中出现2次
        {//将单词i接在后面 
            exist[i]++;//单词i出现次数增加1
            lgLen += len[i] - len[lw] + cp[lw][i];//增加的长度。见思路3.2
            addWordToLg(i);//尝试添加下一个单词
            exist[i]--;//还原状态
            lgLen -= len[i] - len[lw] + cp[lw][i];
        }
    }
}
int main()
{
    cin >> n;
    for(int i = 0; i < n; ++i)
    {
        cin >> word[i];
        len[i] = strlen(word[i]);
    }
    cin >> sc;//输入初始字符
    initCp();//初始化最大接合点数组
    for(int i = 0; i < n; ++i)
    {
        if(word[i][0] == sc)//如果第i单词首字母是sc
        {//把单词i加入龙 
            lgLen = len[i];
            exist[i]++;
            addWordToLg(i);//尝试把下一个单词加入龙
            exist[i]--;//还原
        }
    }
    cout << mxLgLen;
    return 0;
}
解法2:使用string类,每次循环寻找重合部分
#include<bits/stdc++.h>
using namespace std;
#define N 25 
int n, totLen, mxLen;//totLen:龙当前长度 mxLen:龙最大长度 
string s[N];//s[i]:单词列表第i个单词 
int vis[N];//vis[i]:单词s[i]用了几次 
void dfs(string ls)//ls:当前龙中最后字符串 
{
    mxLen = max(totLen, mxLen);//取可能的最大的长度 
    for(int i = 1; i <= n; ++i)
    {
        if(vis[i] < 2)//只要用了不足2次 
        {
            int len;//ls与s[i]重合部分的长度 
            for(len = 1; len < ls.length() && len < s[i].length(); ++len)//由于重合部分不能包含单词,所以重合部分长度要小于两单词的长度 
            {//将ls末尾len个字符截取出来,看和s[i]前len个字符是否相同 
                if(ls.substr(ls.length()-len, len) == s[i].substr(0, len))//只要找到一个可以接上的情况,就不再找了,再找到的不会是最长的龙 
                    break;
            }
            if(len < ls.length() && len < s[i].length())//从上面循环中间跳出,表明s[i]可以接在ls后面。如果不满足该条件,说明循环运行到了最后,没有重合部分。 
            {
                vis[i]++;//s[i]多用了1次 
                totLen += s[i].length() - len;//总长度增加s[i].length() - len
                dfs(s[i]);
                totLen -= s[i].length() - len;//恢复状态 
                vis[i]--; 
            }
        }
    }
}
int main()
{
    char stch;//起始字符 
    cin >> n;
    for(int i = 1; i <= n; ++i)
        cin >> s[i];
    cin >> stch;
    for(int i = 1; i <= n; ++i)
    {
        if(s[i][0] == stch)//如果起始字符和s[i]首字符相同 
        {//以s[i]起始
            vis[i]++; 
            totLen = s[i].length();//当前总长度为s[i]的长度 
            dfs(s[i]);
            vis[i]--;//恢复状态 
        }
    }
    cout << mxLen;
    return 0;
} 
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
题目描述 给出一单词,按照以下规则进行单词接龙: 1.首先任意选定一个单词作为开头; 2.接下来每次接的单词必须满足:它的首字母与上一个单词的尾字母相同; 3.同一个单词不能重复使用; 4.当无法继续接下去时,游戏结束。 你的任务是编写一个程序,计算出在给定单词集合中,最长的单词接龙长度。 输入格式 输入文件的第一行为一个整数n,表示单词的个数。 接下来n行,每行一个单词,由小写字母成,长度不超过20个字符。 输出格式 输出文件仅一行,包含一个整数,表示最长的单词接龙长度。 数据范围 1≤n≤500 输入样例 5 ab bc cd de ef 输出样例 5 提示 输入样例2: 6 a b c d e f 输出样例2: 1 输入样例3: 4 aa bb cc dd 输出样例3: 2 输入样例4: 4 a b ba ab 输出样例4: 2 输入样例5: 3 a aa aaa 输出样例5: 1 输入样例6: 3 a aa ab 输出样例6: 2 输入样例7: 4 a aa aaa aaaa 输出样例7: 1 输入样例8: 4 a aa aaa baaa 输出样例8: 2 输入样例9: 4 a aa baa ab 输出样例9: 2 输入样例10: 4 a aa baa ba 输出样例10: 2 输入样例11: 4 a aa baa bb 输出样例11: 2 输入样例12: 4 a aa baa bc 输出样例12: 2 输入样例13: 4 a aa baa bca 输出样例13: 2 输入样例14: 4 a aa baa bcb 输出样例14: 2 输入样例15: 4 a aa baa bcc 输出样例15: 2 输入样例16: 4 a aa baa bcdc 输出样例16: 2 输入样例17: 4 a aa baa bcde 输出样例17: 2 输入样例18: 4 a aa baa bcdef 输出样例18: 2 输入样例19: 4 a aa baa bcdefg 输出样例19: 2 输入样例20: 4 a aa baa bcdefgh 输出样例20: 2 输入样例21: 4 a aa baa bcdefghi 输出样例21: 2 输入样例22: 4 a aa baa bcdefghij 输出样例22: 2 输入样例23: 4 a aa baa bcdefghijk 输出样例23: 2 输入样例24: 4 a aa baa bcdefghijkl 输出样例24: 2 输入样例25: 4 a aa baa bcdefghijklm 输出样例25: 2 输入样例26: 4 a aa baa bcdefghijklmn 输出样例26: 2 输入样例27: 4 a aa baa bcdefghijklmno 输出样例27: 2 输入样例28: 4 a aa baa bcdefghijklmnop 输出样例28: 2 输入样例29: 4 a aa baa bcdefghijklmnopq 输出样例29: 2 输入样例30: 4 a aa baa bcdefghijklmnopqr 输出样例30: 2 输入样例31: 4 a aa baa bcdefghijklmnopqrs 输出样例31: 2 输入样例32: 4 a aa baa bcdefghijklmnopqrst 输出样例32: 2 输入样例33: 4 a aa baa bcdefghijklmnopqrstu 输出样例33: 2 输入样例34: 4 a aa baa bcdefghijklmnopqrstuv 输出样例34: 2 输入样例35: 4 a aa baa bcdefghijklmnopqrstuvw 输出样例35: 2 输入样例36: 4 a aa baa bcdefghijklmnopqrstuvwx 输出样例36: 2 输入样例37: 4 a aa baa bcdefghijklmnopqrstuvwxy 输出样例37: 2 输入样例38: 4 a aa baa bcdefghijklmnopqrstuvwxyz 输出样例38: 2 输入样例39: 4 a aa baa bcdefghijklmnopqrstuvwxyzA 输出样例39: 2 输入样例40: 4 a aa baa bcdefghijklmnopqrstuvwxyzAB 输出样例40: 2 输入样例41: 4 a aa baa bcdefghijklmnopqrstuvwxyzABC 输出样例41: 2 输入样例42: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCD 输出样例42: 2 输入样例43: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDE 输出样例43: 2 输入样例44: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEF 输出样例44: 2 输入样例45: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFG 输出样例45: 2 输入样例46: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGH 输出样例46: 2 输入样例47: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHI 输出样例47: 2 输入样例48: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJ 输出样例48: 2 输入样例49: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJK 输出样例49: 2 输入样例50: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKL 输出样例50: 2 输入样例51: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM 输出样例51: 2 输入样例52: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN 输出样例52: 2 输入样例53: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO 输出样例53: 2 输入样例54: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP 输出样例54: 2 输入样例55: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ 输出样例55: 2 输入样例56: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR 输出样例56: 2 输入样例57: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS 输出样例57: 2 输入样例58: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST 输出样例58: 2 输入样例59: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU 输出样例59: 2 输入样例60: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV 输出样例60: 2 输入样例61: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW 输出样例61: 2 输入样例62: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX 输出样例62: 2 输入样例63: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY 输出样例63: 2 输入样例64: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 输出样例64: 2 输入样例65: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZA 输出样例65: 2 输入样例66: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZAB 输出样例66: 2 输入样例67: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABC 输出样例67: 2 输入样例68: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCD 输出样例68: 2 输入样例69: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDE 输出样例69: 2 输入样例70: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF 输出样例70: 2 输入样例71: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG 输出样例71: 2 输入样例72: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGH 输出样例72: 2 输入样例73: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHI 输出样例73: 2 输入样例74: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJ 输出样例74: 2 输入样例75: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJK 输出样例75: 2 输入样例76: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL 输出样例76: 2 输入样例77: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM 输出样例77: 2 输入样例78: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN 输出样例78: 2 输入样例79: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO 输出样例79: 2 输入样例80: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP 输出样例80: 2 输入样例81: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ 输出样例81: 2 输入样例82: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQR 输出样例82: 2 输入样例83: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRS 输出样例83: 2 输入样例84: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRST 输出样例84: 2 输入样例85: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU 输出样例85: 2 输入样例86: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUV 输出样例86: 2 输入样例87: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVW 输出样例87: 2 输入样例88: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX 输出样例88: 2 输入样例89: 4 a aa baa bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY 输出样例89: 2 输入样例90: 4
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值