P1019 单词接龙(dfs,洛谷,java)

洛谷链接:https://www.luogu.com.cn/problem/P1019

P1019 单词接龙(dfs,洛谷,java)_第1张图片
P1019 单词接龙(dfs,洛谷,java)_第2张图片

import java.util.Scanner;
public class Main {
	
	static int n=0;  //单词数
	static char ch;         //开头字母
	static String[] str=new String[30];  //储存字符串
	static int[][] yc=new int[30][30];  //两个字母的最小重叠部分
	static int[] vis=new int[30];       //判断单词使用频率
	
	//mt函数,返回x单词后连接一个y单词的最小重叠部分 
	public static int mt(int x,int y) {
		boolean pp=true;
		int ky=0;
		for(int k=str[x].length()-1;k>=0;k--) {
			//从x单词尾部向前看看最小重叠部分是从哪里开始的,以为因为是倒着来,所以保证是最小的
			for(int kx=k;kx<str[x].length();kx++) {
				if(str[x].charAt(kx)!=str[y].charAt(ky++)) {
					pp=false;
					break;
				}
			}
			if(pp==true) {
				//如果说当前以k为开头的前一个单词后缀 ,是后面单词的前缀,就马上返回重叠部分。(tr[x].size()-k是找出来的规律)
			    return str[x].length()-k;
			}
			//重置
			ky=0;
			pp=true;
		}
		return 0;
	} 
	
	static int ans=-1;  //答案
	static int an=0;    //每次搜到的当前最长串
	
	//p为尾部单词编号(p的后缀就是“龙”的后缀,因为p已经连接到”龙“后面了)
	public static void dfs(int p) {
		boolean jx=false;
		for(int j=1;j<=n;j++) {
			if(vis[j]>=2) continue;  //使用了两次就跳过
			if(yc[p][j]==0) continue;  //两单词之间没有重合部分就跳过
			if(yc[p][j]==str[p].length()  ||  yc[p][j]==str[j].length()) {
				//两者存在包含关系就跳过 
				continue;
			} 
			
			an+=str[j].length()-yc[p][j];  //两单词合并再减去最小重合部分 
			vis[j]++;                      //使用了一次
			jx=true;                       //标记一下当前已经成功匹配到一个可以连接的部分 
			dfs(j);                        //接上去
			an-=str[j].length()-yc[p][j];  //回溯,就要再减回去那一部分长度
			vis[j]--;                      //回溯,使用-- 
		}
		if(jx==false) {
			ans=Math.max(ans,an);
		}
		return;
	}
	
	public static void main(String[] args) {	
		Scanner in=new Scanner(System.in);
		//输入
        n=in.nextInt();
        for(int i=1;i<=n;i++) {
        	str[i]=in.next();
        }
        ch=in.next().charAt(0);
        
        //预处理yc数组。yc[i][j]就表示,i单词后连接一个j单词的最小重叠部分 
        //比如 i表示at,j表示att. yc[i][j]就为2 但是yc[j][i]就为0.
        //预处理是一个关键
        for(int i=1;i<=n;i++) {
        	for(int j=1;j<=n;j++) {
            	yc[i][j]=mt(i,j);
        	}
        }
        
        for(int i=1;i<=n;i++) {  //从头到尾看一下有没有以指定开头字母为开头的单词
        	if(str[i].charAt(0)==ch) {  //如果有,就以当前单词为基准进行搜索。 
        		vis[i]++;            //使用过一次
        		an=str[i].length();  //更新当前串长度
        		dfs(i);              //接上
        		vis[i]=0;            //消除影响
        	}
        }
        
        System.out.println(ans);
	}
}

你可能感兴趣的:(算法题)