嘿嘿,低产博主又来更新了>︿<
这次是dfs搜索的题,我是看另一个博主写的,自己来归纳一下啦~冲冲冲!!!
参考博客:https://www.cnblogs.com/zbx2000/p/12715400.html
问题概述
1.已知一组单词
2.给定一个开头的字母
3.要求出以这个字母开头的最长的“龙”
4.每个单词都最多在“龙”中出现两次 5.两个单词重合部分合为一部分
6.另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=21;
int n;//单词数
string str[N];//怎么说也要让输入的那些单词有 地方住呀
//这里的N表示单词数的最多的个数限度
int g[N][N]={0};//两个单词之间能够重合的最短长度
int ans=0;//记录龙的长度
int used[N]={0};//每个单词使用的次数
void dfs(string dragon,int last)
{
ans=max((int)dragon.size(),ans);
//现在龙的长度,强制转换是因为string的size是无符号长整型
used[last]++;//使用次数+1
//寻找它的下一个单词
for(int i=0;i<n;i++)
{
if(g[last][i]&&used[i]<2)//如果跟第i个单词有重复部分,就接上
dfs(dragon+str[i].substr(g[last][i]),i);
}
used[last]--;
//我来解释一下大多数blog都没讲到的为什么要恢复现场
//就好比例子来说,touch是第一个被接上的单词
//那么这个touch在履行完它接龙的责任之后这个循环就结束了呀
//本来是要由于递归回到at的让人家at继续挑选看看能不能接上其他重合的单词的另一条龙
//那么好嘞,你at要接上另一条龙了,就说明龙里面已经不是touch作老二了
//那你是不是要把人家touch还回去,要用的时候再借嘛
//ok,就是这样。
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>str[i];
char sign;
cin>>sign;//给定一个开头字母
//为了枚举字符串之间相同的字串合并形式
//必须有预处理出来的字符串之间的相同子串邻接表
//总不能一遍一遍算吧,得有个表
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)//也有可能跟自己egtact
{
string a=str[i];//当前的单词
string b=str[j];//被对照的单词
for(int k=1;k<min(a.size(),b.size());k++)
//不用等于是因为不能是包含关系
//k表示重复的字串的字符个数
{
if(a.substr(a.size()-k)==b.substr(0,k))
//求最小相同字串才能得出最长的龙
//重合的越多,龙越短
{
g[i][j]=k;
break;
}
}
}
}
for(int i=0;i<n;i++)//从第一个单词开始
{
if(str[i][0]==sign)
dfs(str[i],i);
//第一个参数代表现在的龙的现状
//第二个参数代表此时操作的单词的坐标
}
cout<<ans;
return 0;
}
学会的技巧:
- 具有重要意义的统一变量最好写在头文件 下来的地方作为全局变量;
- 我今天才用到!!!原来字符串数组我不用再char[][]了!!!!——直接用string str[];
- const int 还是很实用的;
- 我觉得以后i,j这种局部变量还是不要搞成全局变量比较好,容易乱掉,相信我,要用的时候再设。
- substr(i,j)——表示从下标i开始截取j位
- substr(i)——表示从i到结尾的字符串
- 利用加号直接连接两个字符串常量,会直接把两个字符连接起来
附上一张萨摩美照


183

被折叠的 条评论
为什么被折叠?



