• 【luogu】p1019 单词接龙


    (碎碎念:初二的时候就开始写这道题,写了几天觉得啊好烦啊就不想写就放弃了,上初三之后终于抽出时间把这个题写完了
    (搜索题要我狗命(缩成一团

    题目链接:

    https://www.luogu.com.cn/problem/P1019

    题目描述

    单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。

    输入格式

    输入的第一行为一个单独的整数n (n≤20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.

    输出格式

    只需输出以此字母开头的最长的“龙”的长度

    分析

    由于题目中给出的数据范围单词数n<=20很小,可以用搜索dfs去解决

    按照给出的字母,我们先确定好一个单词作为开头

    枚举剩下的且使用没有超过两次的单词

    对于每一个单词再枚举他的与前面单词相接位数并判断是否可行(要注意一个单词并不能完全包含在另一个单词中)。

    如果他可以接在前一个单词上,

    就先将它接入后增加的位数累加进最后的答案中,再去搜索下一个可以接上的单词。

    边界状态:

    当一个单词后无法再接入任何一个单词

    我们就把答案与之前得到的最大答案进行比较取两者中最大值。

    AC Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<string> 
    using namespace std;
    int read(){
    	int a = 0,f = 0;char p = getchar();
    	while(!isdigit(p)){f|=p=='-';p = getchar();}
    	while(isdigit(p)){a = (a<<3) + (a<<1) + (p^48);p = getchar();}
    	return f?-a:a;
    }
    char c[25][100];//存单词
    int ans;//记录每一种情况的答案
    int flag[10000];//标记这个单词已经用过次数 
    int Ans,n; //统计最终的答案 读入单词个数
    bool Flag = 0;//判断一个单词后面是否还可以继续接入单词
    void dfs(int x){//dfs!
    	Flag = 0;
    	for(int i = 1;i <= n;i ++){//尝试把i接在x的后面
    		if(flag[i] == 2)continue;
    		int leni = strlen(c[i]),lenx = strlen(c[x]);//记录两个单词长度 
    		int cd = min(leni,lenx)-1;//最多能接在一起的长度为两个单词长度最小值-1
    		int cd1,tot;
    		int jl = 1;//记录我们想要接入几位
    		while(jl <= cd){
    			cd1 = jl,tot = 0;
    			//int now = 0;
    			while(cd1){//目前判断到的位置
    				if(c[x][lenx-cd1] != c[i][jl-cd1])break;
    				else tot++;
    				cd1--;	
    			}
    			if(tot == jl)break;//两个可以接在一起
    			jl++;
    		}
    		if(tot == jl && tot != 0){//记录下来并且去搜索下一个
    			//cout<<x<<" "<<i<<" "<<tot<<endl;
    			Flag = 1;
    			ans += (leni-jl);
    			flag[i] ++;
    			dfs(i);
    			ans -= (leni-jl);
    			flag[i] --; 
    		} 
    	}
    	if(Flag == 0){//后面什么也没法接的时候 
    	
    		Ans = max(ans,Ans);
    	}
    }
    int main(){
    	n = read();
    	for(int i = 1;i <= n;i++)
    		scanf("%s",&c[i]);
    	
    	char a;
    	cin >> a;
    	for(int i = 1;i <= n;i++){
    		if(c[i][0] == a){
    			//cout<<c[i]<<endl;
    			flag[i]++;
    			ans = strlen(c[i]);
    			dfs(i);
    		}
    	}
    	cout << Ans;
    }
    

    注意(不过可能也就我这么憨憨才会错的一个地方)

    我们在枚举他可以接入的位数时,应该从小到大进行枚举,在能让两个单词相接的情况下,让相接的部分尽可能的小

    比如:
    abababab和abababc

    如果我们从大到小枚举它可以接入的部分那么最后相接就会变为

    ababababc 有9位

    但我们从小到大枚举得到的才是最长的情况

    ababababababc 有13位

    好了好了没了没了别看了

  • 相关阅读:
    jdk1.8StreamApi
    Python 【类的创建和类的实例化】
    Python【网络编程】
    Python 【图片转字符画】
    echarts 【图表的基本使用】
    Java 【Math】
    Java 【循环语句】
    Java 【instanceof使用】
    java【第三课 条件语句】
    Java【第二课 扫描仪 & 布尔数据类型】
  • 原文地址:https://www.cnblogs.com/huixinxinw/p/12183210.html
Copyright © 2020-2023  润新知