单词接龙

博客内容讲述了利用回溯法解决单词接龙问题的思路,提及遇到的困难和解决方案,包括在遇到错误时如何调整代码以符合提交要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


单词接龙:是指一组单词序列,任何两个相邻的单词满足前一个单词的尾字母和后一个单词的首字母相同。 

接龙长度:接龙中所有单词长度之和。 

如单词:tea, cat, dog, aid, fish

可以形成单词接龙:cat tea aid dog

其中cat为龙头,dog为龙尾 

接龙包含的单词个数为4

接龙长度为12

规格说明:

  • 单词由全小写字母组成,以字符串形式给定,即以’\0’结束(用例保证 

  • 单词长度和数量均无限制 

  • 一条单词接龙中每个单词只能使用一次 

功能说明:

定义 

1最少接龙:单词数量最少的接龙 

2最短接龙:长度最短的接龙 

给定一套单词库,请根据指定的龙头和龙尾,实现以下功能: 

1、计算最少接龙包含的单词个数 

2、计算最短接龙的长度 

示例: 

单词库由ab,beeec,bd,dc,cb五个单词组成,以ab为龙头,cb为龙尾的接龙中: 

最少接龙:ab beeec cb(含有3个单词) 

最短接龙:ab bd dc cb(接龙长度为8

 

功能:添加单词

输入:单词

输出:无

 

功能:获取最少接龙的单词个数

输入:head 龙头 

     tail     龙尾 

输出:单词个数(如果不能形成接龙、指定龙头龙尾不存在、龙头龙尾相同等,返回-1 

 

功能:获取最短接龙的长度

输入:head 龙头 

     tail     龙尾 

输出:接龙的长度(如果不能形成接龙、指定龙头龙尾不存在、龙头龙尾相同等,返回-1 

 

 

 
知识点:  
题目来源:  内部整理 
练习阶段:  挑战 
运行时间限制: 10Sec
内存限制: 128MByte
输入:  

添加的一组单词序列,一行字符串,每个单词以空格隔开,如ab beeec bd dc cb

获取最少接龙的单词个数和获取最短接龙的长度,一行字符串,包括2个单词,分别是龙头单词和龙尾单词,如ab cb

 
输出:  

2个整数,获取最少接龙的单词个数和获取最短接龙的长度,一个空格隔开

 
样例输入:
ab beeec bd dc cb
ab cb
                   
样例输出:
3 8
                    
答案提示:

 

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

	/**
	 * @param args
	 */
	public static String head ="";
	public static String end ="";
	public static List<String> result = new ArrayList();
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scan = new Scanner(System.in);// 接收控制台输入的信息
		String str = scan.nextLine();
		
		String headend = scan.nextLine();
		String[] myarr = headend.split(" ");
		
		List<String> my = new ArrayList();
		String[] arr = str.split(" ");
		for(int i = 0;i<arr.length;i++)
		{
			my.add(arr[i]);
		}
	//============= 指定龙头龙尾不存在	
		int flag=0;
		for(int i=0;i<my.size();i++)
		{
			for(int j=0;j<myarr.length;j++)
			{
				if(my.get(i).equals(myarr[j]))
					flag++;
			}
		}
		if(flag!=2)
		{
			System.out.println(-1+" "+-1);
			System.exit(0);
		}
	//=============龙头龙尾相同等
		if(myarr[0].equals(myarr[1]))
		{
			System.out.println(-1+" "+-1);
			System.exit(0);
		}
//qudiao去掉 list中 龙头龙尾		
		for(int i=0;i<my.size();i++)
		{
			for(int j=0;j<myarr.length;j++)
			{
				if(my.get(i).equals(myarr[j]))
					my.remove(i);
			}
		}
		
		
//		System.out.println(my.toString());// 参与接龙的单词
//		System.out.println(myarr[0]+myarr[1]);//龙头,龙尾
		head=myarr[0];
		end = myarr[1];
		jielong(0,my);
		
		int min=Integer.MAX_VALUE;
		
		for(int i = 0;i<result.size();i++)//单词个数
		{
			String[] resultarr = result.get(i).split(",");
			if(resultarr.length<min)
				min = resultarr.length;
		}
		int minlength=Integer.MAX_VALUE;
		for(int i = 0;i<result.size();i++)//最短接龙长度
		{
			String temp=result.get(i).replace(",", "");
			if(temp.length()<minlength)
				minlength = temp.length();
				
		}
		
		if(min==Integer.MAX_VALUE&&minlength==Integer.MAX_VALUE)
		{
			if(iscontinue(head,end))
			{
				System.out.println(2+" "+(head.length()+end.length()));
			}
			else
			{
				System.out.println(-1+" "+-1);
			}
		}
		else
		{
			if(iscontinue(head,end))
			{
				System.out.println(2+" "+(head.length()+end.length()));
			}
			else
				System.out.println(min+" "+minlength);
		}
	}
	
	
	
	public static  void jielong(int i,List<String> my) 
	{
		for(int j=0;j<my.size();j++)
		{
			if(iscontinue(head,my.get(j)))
			{
				String temphead = head;
				head=head+","+my.get(j);
				String temp = my.get(j);
				my.remove(j);
				if(!iscontinue(head,end))
					jielong(i+1,my);
				else
				{
//					System.out.println(head+","+end);
					result.add(head+","+end);
				}
				head=temphead;
				my.add(i, temp);
				
			}
		}
	}
	
	
	public static boolean iscontinue(String begin,String end)
	{
		if(begin.charAt(begin.length()-1)==end.charAt(0))
			return true;
		else
			return false;
	}

}

主要用回溯法,和8皇后类似

开始有3个用例没有过,实在是检查不出来,每次只能提交一次真是坑爹,后来搜了下论坛上,看别人说错误要输出-1,-1;就改成这样了,不知道能不能通过


这是论坛上别人c++代码,貌似通过了,懒得试了

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
void Find_Shortest_Path(int v,int *dist,bool len_or_count);
typedef struct Node
{
 string word;      //存储单词
 struct Node *next;
    int index;        //存储该节点在容器中索引,图中每一个节点有一个唯一的索引值,一个节点的邻接节点构成单链表中节点的index值就是对应的
}NODE;                //指针数组中(或说图中)的索引为index的节点,单链表中的节点其实是图中节点的副本,索引(编号)一样  ,都表示index这个节点
bool *flag_str;       //存储某个节点是否被访问过的标志,这个标志必须单独,不能放到上面的节点中
vector<NODE *> nodvec; //头节点容器
int f_index,l_index;              //存储龙头和龙尾在容器中的索引
int result_len=60000,result_count=60000;  //查找的结果
int main()
{
 string line,temp,first,last;
 vector<string> vec; 
 int index=0;
    getline(cin,line);
 istringstream istr(line);
 while(istr>>temp)
  vec.push_back(temp);
 sort(vec.begin(),vec.end());
 vector<string>::iterator iter=unique(vec.begin(),vec.end());
 vec.erase(iter,vec.end());
 cin>>first>>last;
 iter=vec.begin();
 bool f_flag=false,l_flag=false;
 while(iter!=vec.end())          //判断龙头和龙尾单词是否存在,是否相等
 {
     if(*iter==first)
  { 
   f_flag=true;
   f_index=iter-vec.begin();
  }
  if(*iter==last)
  { 
   l_flag=true;
   l_index=iter-vec.begin();
  }
     ++iter;
 }
 if(first==last || !(f_flag && l_flag))
 {
  cout << -1 << " "  << -1 << endl;
return -1;
 }
 iter=vec.begin();
 flag_str=new bool[vec.size()]();    //动态分配标志数组,标示某个节点是否已经加入到最短路径中
 while(iter!=vec.end())    //将头节点的地址放到一个容器中
 {
  NODE *p=new NODE();
  p->word=*iter;
  p->next=NULL;
  p->index=index++;
  flag_str[p->index]=false;
  nodvec.push_back(p);
  ++iter;
 }
 vector<NODE *>::iterator pfiter=nodvec.begin(),psiter=nodvec.begin();
 while(pfiter!=nodvec.end())      //形成图
 {
  psiter=nodvec.begin();
  while(psiter!=nodvec.end())
  {
   if((*pfiter)->word!=(*psiter)->word)  //不要让自己是自己的后继
   {
    if((*psiter)->word[(*psiter)->word.length()-1]==(*pfiter)->word[0])
    {
     NODE *p=*psiter;
     while(p->next!=NULL) 
      p=p->next;
     NODE *q=new NODE();
     q->index=(*pfiter)->index;
     q->word=(*pfiter)->word;
     q->next=NULL;
     p->next=q;
    }
   }
   ++psiter ;
  }
     ++pfiter;
 }
 int *dist=new int[nodvec.size()]();
 Find_Shortest_Path(f_index,dist,false);   //查找单词接龙所有路径中单词的最少个数
 for(int i=0;i<vec.size();i++)
  flag_str[i]=false;
 Find_Shortest_Path(f_index,dist,true);    //查找单词接龙所有路径中总单词的最小长度
 for(int i=0;i<nodvec.size();i++)    //释放内存
 {
     NODE *p,*q;
  q=nodvec[i];
  p=q->next;
  delete q;
  while(p!=NULL)
  {
      q=p;
   p=p->next;
   delete q;
  }
 }
 delete [] flag_str;
 delete [] dist;
 if(result_len==60000 || result_count==60000)
 {
  cout << -1 << " "  << -1 << endl;
return -1;
 }
 else
     cout<<result_count<<" "<<result_len<<endl;
}
//查找路径中总单词长度最短的
//查找从源节点到其他所有顶点的最短路径的过程中,找到我的目标顶点就结束查找
void Find_Shortest_Path(int v,int *dist,bool len_or_count)  //v是容器中的索引,实际对应一个节点,dist是动态分配的一个数组,元素个数是图节点的个数
{                                         //dist[i]存储源结点v到节点i的最短路径的长度 
 vector<NODE *>::iterator iter;
 iter=nodvec.begin();
 NODE *p=nodvec[v]->next;
 //初始化路径长度(单词长度和单词个数)
 while(p!=NULL)  //初始化从头节点能直达的节点
 {
  if(len_or_count)
      dist[p->index]=p->word.length();
  else
   dist[p->index]=1;
  flag_str[p->index]=true;  //标示为true的为已经初始化的节点,后面要重新置为false
  p=p->next;
 }
 while(iter!=nodvec.end())     //初始化从头节点不能直达的节点
 {
  if((*iter)->index!=v)   //自己的不搜索
  {
   if(flag_str[(*iter)->index])
    flag_str[(*iter)->index]=false;
   else
    dist[(*iter)->index]=60000;    
  }
  else                    //置自己的标志
   flag_str[(*iter)->index]=true;
     ++iter;
 }
 for(int i=1;i<nodvec.size();i++)  //总共要查找的次数为nodvec.size()-1次,当查找到目标节点,也直接结束
 {
     int minval=60000;
     int vt=v;
  for(int j=0;j<nodvec.size();j++)
  {
   if(!flag_str[nodvec[j]->index] && dist[j]<minval)
   {
       vt=j;
    minval=dist[j];
   }
  }
  flag_str[nodvec[vt]->index]=true;
  p=nodvec[vt]->next;
  while(p!=NULL)
  {
   if(!flag_str[p->index] && minval+p->word.length()<dist[p->index])
   {
    if(len_or_count)
       dist[p->index]=minval+p->word.length();
    else
       dist[p->index]=minval+1;
   }
   p=p->next;
  }
     if(vt==l_index)   //已经找到了目标了
  {
   if(len_or_count)   
       result_len=dist[vt]+nodvec[v]->word.length();
   else
    result_count=dist[vt]+1;
   break;
  }
 }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值