P1019 单词接龙
题目分析题目大意解题思路
代码传送门
题目
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beastbeast和astonishastonish,如果接成一条龙则变为beastonishbeastonish,另外相邻的两部分不能存在包含关系,例如atat 和 atideatide 间不能相连。
输入格式: 输入的第一行为一个单独的整数nn (n \le 20n≤20)表示单词数,以下nn 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式: 只需输出以此字母开头的最长的“龙”的长度
输入输出样例 输入样例#1:
5
at
touch
cheat
choose
tact
a
输出样例#1:
23
分析
题目大意
题目很好理解,单词接龙,需要注意的是题目给出了“龙头”,并且这个龙头是真的,也就是说需要按照这个龙头去找第一个单词,不然可能通过不了。
解题思路
每个单词可以使用两次,所以需要一个数组去存储每个单词被访问的次数,作为递归边界的判定依据。根据题意,我们还需要知道每个单词后缀与每个单词前缀重叠的最小长度,这里是单独写了一个函数,在每次遍历的时候进行调用。其余就是dfs的事了,具体细节可以见我的代码注释。
代码
#include<iostream>
#include<string>
#include<algorithm>
using namespace std
;
const int M
= 20+5;
int n
;
string words
[M
];
int vis
[M
];
int ans
= 0;
int cmp(string a
,string b
){
int l
= (int)min(a
.length(), b
.length());
for(int i
= 1; i
< l
; i
++) {
int j
;
int flag
= 1;
for(int j
= 0; j
< i
; j
++)
if(a
[a
.length() - i
+ j
] != b
[j
])
flag
= 0;
if(flag
)
return i
;
}
return 0;
}
void dfs(string s
,int l
){
ans
= max(ans
,l
);
for(int j
= 0;j
< n
;j
++){
if(vis
[j
] >= 2){
continue;
}
int c
= cmp(s
,words
[j
]);
if(c
> 0){
vis
[j
]++;
dfs(words
[j
],l
+words
[j
].length()-c
);
vis
[j
]--;
}
}
}
int main(){
cin
>>n
;
for(int i
= 0;i
< n
+1;i
++){
cin
>>words
[i
];
}
dfs(" "+words
[n
],1);
cout
<<ans
<<endl
;
return 0;
}
传送门
P1019