P1019 单词接龙
题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beastbeast和astonishastonish,如果接成一条龙则变为beastonishbeastonish,另外相邻的两部分不能存在包含关系,例如atat 和 atideatide 间不能相连。
输入格式
输入的第一行为一个单独的整数nn (n \le 20n≤20)表示单词数,以下nn 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式
只需输出以此字母开头的最长的“龙”的长度
输入样例
5
at
touch
cheat
choose
tact
a
输出样例
23
题解
import java.util.Scanner;
public class Main {
public static int n;
public static String inStr[] = new String[21];//存储字符串
public static int length = 0;//记录结果字符串长度
public static int flag[] = new int[21];//存储字符串用过的次数
//返回重叠部分的长度
public static int Splicing(String left, String right) {
for(int i=left.length()-1,k=1;i>=1;i--,k++) {
if (right.length()-k > 0) {
if(left.substring(i, left.length()).contains(right.substring(0, k))) {
return k;
}
}
}
return 0;
}
//回溯主体
public static void Search(String now, int nowlength) {
//判断长度
if(nowlength > length) length = nowlength;
//横向搜索
for(int i=0;i<n;i++) {
//判断用过的字符串次数
if(flag[i]>=2) continue;
int k = Splicing(now, inStr[i]);
//纵向搜索
if(k > 0) {
flag[i]++;
Search(inStr[i],nowlength+inStr[i].length()-k);
flag[i]--;
}
}
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
for(int i=0;i<=n;i++) {
inStr[i] = scanner.next();
}
for(int i=0;i<n;i++) {
if(inStr[i].startsWith(inStr[n])) {
flag[i]++;//第一个单词也要记得加使用次数
Search(inStr[i], inStr[i].length());
flag[i]--;
}
}
System.out.println(length);
scanner.close();
}
}
总结
大致了解了深搜的规律之后,这道题也比较容易理解和解决了。我们来理解一下题意,这道题的目的得到是一个整数,即“龙”的长度。然后可以看到它给出的限制每个单词只能出现两次,取最长的“龙”。所以在我们的回溯主体要有两个判断,第一个是判断长度取最长,第二个是判断单词是否出现两次。解决这两个判断之后,不断回溯即可得到正确结果。在这里面有一个单词拼接的操作,我们单独写出一个函数来执行这个操作,因为题目所求只是长度,所以这个拼接函数返回两个单词的最小重叠的长度即可。