【题目链接】

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出现次数增加1lgLen += len[i] - len[lw] + cp[lw][i];//增加的长度。见思路3.2addWordToLg(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() - lendfs(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;
}

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

  1. 信息学奥赛一本通 1239:统计数字 | 1847:【07NOIP提高组】统计数字 | OpenJudge NOI 2.4 7909 | 洛谷 P1097 [NOIP2007 提高组] 统计数字

    [题目链接] ybt 1239:统计数字 ybt 1847:[07NOIP提高组]统计数字 一本通中限制不许使用STL,那么引入头文件不能写<bits/stdc++.h>,只能写<i ...

  2. 信息学奥赛一本通 1118:铺地毯 | 1863:【11NOIP提高组】铺地毯 | OpenJudge NOI 1.9 14 | 洛谷 P1003 [NOIP2011 提高组] 铺地毯

    [题目链接] ybt 1118:铺地毯 ybt 1863:[11NOIP提高组]铺地毯 OpenJudge NOI 1.9 14:铺地毯 洛谷 P1003 [NOIP2011 提高组] 铺地毯 [题目 ...

  3. 信息学奥赛一本通 1407:笨小猴 | 1851:【08NOIP提高组】笨小猴 | OpenJudge NOI 1.9 06 | 洛谷 P1125 [NOIP2008 提高组] 笨小猴

    [题目链接] ybt 1407:笨小猴 ybt 1851:[08NOIP提高组]笨小猴 OpenJudge NOI 1.9 06:笨小猴 洛谷 P1125 [NOIP2008 提高组] 笨小猴 [题目 ...

  4. 信息学奥赛一本通 1180 | 1946:【09NOIP普及组】分数线划定 | OpenJudge NOI 1.10 05 | 洛谷 P1068 [NOIP2009 普及组] 分数线划定

    [题目链接] ybt 1180:分数线划定 ybt 1946:[09NOIP普及组]分数线划定 OpenJudge NOI 1.10 05:分数线划定 洛谷 P1068 [NOIP2009 普及组] ...

  5. 信息学奥赛一本通 1820:【00NOIP提高组】进制转换 | 洛谷 P1017 [NOIP2000 提高组] 进制转换

    [题目链接] ybt 1820:[00NOIP提高组]进制转换 洛谷 P1017 [NOIP2000 提高组] 进制转换 注意:两OJ上题目内容相同,输入输出要求不同 [题目考点] 1.数制 [解题思 ...

  6. 信息学奥赛一本通 1130:找第一个只出现一次的字符 | OpenJudge NOI 1.7 02

    [题目链接] ybt 1130:找第一个只出现一次的字符 OpenJudge NOI 1.7 02:找第一个只出现一次的字符 [题目考点] 1. 字符串 2. 散列存储 [解题思路] 依据散列存储思想 ...

  7. 信息学奥赛一本通 1089:数字反转 | 1953:【11NOIP普及组】数字反转 | OpenJudge NOI 1.5 29 | 洛谷 P1307 [NOIP2011 普及组] 数字反转

    [题目链接] ybt 1089:数字反转 ybt 1953:[11NOIP普及组]数字反转 OpenJudge NOI 1.5 29:数字反转 洛谷 P1307 [NOIP2011 普及组] 数字反转 ...

  8. 信息学奥赛一本通 1098:质因数分解 | 1957:【12NOIP普及组】质因数分解 | OpenJudge NOI 1.5 43 | 洛谷 P1075 [NOIP2012 普及组] 质因数分解

    [题目链接] ybt 1098:质因数分解 ybt 1957:[12NOIP普及组]质因数分解 OpenJudge NOI 1.5 43:质因数分解 洛谷 P1075 [NOIP2012 普及组] 质 ...

  9. P1019 [NOIP2000 提高组] 单词接龙

    P1019 [NOIP2000 提高组] 单词接龙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 整体思路:1.先将每个单词与另外的单词重叠的部分算出来记作yc[][]: 2.然后 ...

最新文章

  1. java中的几个概念的比较
  2. 2. VS使用---HelloWorld
  3. oracle按照时间过滤
  4. 先验概率、似然函数与后验概率
  5. python对json的操作总结
  6. 一天的学习成果:hash输出,dcache工作原理,include的home directory,fist optype的含义...
  7. dropify,不错的图片上传预览插件
  8. lintcode 最长上升连续子序列 II(二维最长上升连续序列)
  9. C#单例模式的简单使用
  10. 桌面环境选择_Ubuntu 18.04 桌面环境初体验
  11. linux awk 脚本格式,偷偷学习shell脚本之awk编辑器
  12. SQL存储过程与自定义函数实例
  13. python游戏房间_Python House冒险-如果已经进入一个房间,如何给出不同的输出
  14. linux 安装weblogic12.1.3.0步骤
  15. eweishop 人人商城区别_微擎开发之人人商城添加第三方支付系列
  16. 微软苏州研发人员将达4500人!第二幢楼今天开建!
  17. 小秘谈币:谈谈炒币的几点感悟
  18. 4.12 使用反相命令反转图片色彩 [原创Ps教程]
  19. 教育机构课程顾问常见黑话大全
  20. quartus频率计 时钟设置_Quartus II EDA频率计设计

热门文章

  1. 实现库函数strlen和strcpy
  2. Query Layer介绍
  3. [转载]Lua脚本与C++交互
  4. android studio 引入httpclient,HttpClient不会导入Android Studio
  5. linux宝塔登录不上去怎么回事,宝塔面板点击登陆没有用怎么办
  6. 工作这几年,同事对我的称呼肉眼可见的在变化着......
  7. 没想到,我都来阿里5年了!
  8. 最近和前字节跳动大佬聊了聊今年春招面试的变化
  9. 【快讯】JeecgBoot低代码平台,成功入选2021科创中国·开源创新榜
  10. Myeclipse8.5 反编译插件 jad 安装