• 【NOI OJ】8783 单词接龙



    8783:单词接龙


    总时间限制: 
    1000ms 
    内存限制: 
    65536kB
    描述

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

    输入
    输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词(只含有大写或小写字母,长度不超过20),输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
    输出
    只需输出以此字母开头的最长的“龙”的长度。
    样例输入
    5
    at
    touch
    cheat
    choose
    tact
    a
    
    样例输出
    23
    提示
    连成的“龙”为atoucheatactactouchoose
    来源
    NOIP2000复赛 普及组 第四题

    #------------------------------------------------------------------------------#

    此题乍一看,似乎并不是很难,但需要处理以下一些情况:
    1.单词不能包含
    2.每个单词可以用2次
    3.重合部分长度需减去
    4.重合长度是不确定的。

    现在谈谈大体思路:

    首先此题一定用深搜。

    其次存单词时,从f[1]开始存,而最后一个表示开头的字母存f[0]。
    why?我们接龙时就直接从f[0]开始便不需要处理开头的单词。

    接下来处理问题:
    1.关于包含,只需查到长度len-1即可,如果还不符合便不符合。
    2.我们可以定义一个v数组,判断单词使用次数,在使用前判断if(v[i]<2)每使用一次变v[i]++,注意递归完后v[i]--

    然后先看4.在判断单词是否可以连接时,我们从i=0,循环到i=n,即所有单词查完,如果单词可用便接着循环,查待连接单词,如果某一位与可连接单词相同,便再循环,定义一个临时变量t,从后一位开始,查,如果不同,直接t=0,break,出循环后if(t)便代表可连接,开始递归下一个,别忘了v[i]++。(此部分便是核心算法)

    关于3.在判断可连接时,总长度L便加上两个单词长度,然后前面的最后盘点是否完全符合的循环计数变量定义在外面,L直接减去它便是接龙长度了。

    不知道是否听懂……
    直接上代码:

    #include<cstdio>
    #include<cstring>
    struct le//定义结构体可以更方便
    {
    	char s[22];//单词
    	int len;//单词长度
    	int v;//单词访问次数
    }c[22];//单词数量不超过20个,所以c[22]即可
    int n;
    int maxn;
    void jl(int x,int len)//两个参数分别代表待连接单词的结构体下标和长度
    {
    	for(int i=1;i<=n;i++)
    		if(c[i].v<2)//判断访问次数
    			for(int j=0;j<c[x].len;j++)//查待连接单词的每一个字母
    				if(c[x].s[j]==c[i].s[0])
    				{
    					int k=1;//将循环变量定义在外面,方便以后相减
    					int t=1;//临时变量(其实bool就行)
    					for(int l=j+1;l<c[x].len&&k<c[i].len;k++,l++)//l表示待连接单词下标,k是可连接单词下标,所以在循环条件中需满足它们小于(因为不能包含,所以不能等于)单词长度
    						if(c[x].s[l]!=c[i].s[k])
    						{
    							t=0;
    							break;
    						}
    					if(t)
    					{
    						c[i].v++;
    						jl(i,len+c[i].len-k);//更新长度和下标后递归
    						c[i].v--;//完成后一定记得--
    					}
    				}
    	if(len>maxn)
    		maxn=len;//不解释
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",c[i].s);
    		c[i].len=strlen(c[i].s);
    	}
    	scanf("%s",c[0].s);
    	c[0].len=strlen(c[0].s);//直接将开头字母存在0号结构体
    	jl(0,c[0].len);//开头字母当第一个单词处理
    	printf("%d",maxn);
    }

                                                                                                                                                                                   By WZY


  • 相关阅读:
    队列加分项(选作,根据博客质量加1-5分)(补博客)
    队列课下作业(补博客)
    20162319 2017-2018-20162319 《程序设计与数据结构》第7周学习总结
    20162319 补博客——用数组实现循环队列 06.第六周
    20162319 补博客——排序课下作业
    20162319 2017-2018-20162319 《程序设计与数据结构》第5周学习总结
    20162319 2017-2018-20162319 《程序设计与数据结构》第6周学习总结
    20162319 第二学期第一次实验:线性表的应用
    20162314 Experiment 2
    20162314 《Program Design & Data Structures》Learning Summary Of The Seventh Week
  • 原文地址:https://www.cnblogs.com/LinqiongTaoist/p/7203778.html
Copyright © 2020-2023  润新知