NOIP 2000年提高组复赛 单词接龙

(╥╯^╰╥)说起这道题就心酸,几个数据特别坑,几分钟写完的程序花了一个上午调试bug,吐槽完毕,进入正题:

1,需要建立一个标记数组vis表示当前单词被采取的次数;

2,for循环中找到每一个符合条件的龙头,初始化标记数组后进行深度优先搜索;

3,因为连接起来的单词要最长,所以对比是选择从上一个单词的末尾与当前单词的开头进行比对,一旦符合就return

注意!字符相等还不一定符合题意,一定要比到上一个单词的最后一个字符才算符合条件,给出两组数据自己揣摩:

(自己思考后才能有收获吗(~ ̄▽ ̄)~ )

 

1                                       2

envelope                           abababab

e                                       abababc

ans:15                            a                    ans:19

下面在代码中进行分析:

 

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
struct node{
	char lin[1000];
}s[20];  // 结构体 s 用于储存单词 
int t,ans;
int vis[20];  //标记数组,每一次搜索初始化为 0,单词使用一次加一,超过二就不能继续使用 
int len[20];  //单词长度数组,表示每一个单词的长度 
int found(int stp,int i){ //stp代表上一个已经选择的单词下标 i表示当前的单词下标 
	int q,w,j;
	for(q=len[stp]-1;q>=1;q--){   //为使长度最长,从上一个单词的末尾开始搜索 
		if(s[stp].lin[q]==s[i].lin[0]){  //第一个字符匹配后继续看后面还有多少位 
			int x=0;         //相同位数 
			for(w=q,j=0;w<len[stp]&&j<len[i];w++,j++){
				if(s[stp].lin[w]==s[i].lin[j])x++;
				else break;
			}
			if(w==len[stp])return x;//注意!一定要比到上一个字符的最后一个字符答案才有效 
		}
	}
	return 0;
}
void dfs(int stp,int length){ //上一个已经选择的单词  当前的最长单词长度 
	int i;
	bool mark=false;
	for(i=0;i<t;i++){
		if(vis[i]>=2)continue;//单词已经被找过两次,跳过 
		int x=found(stp,i);  //x代表上一个单词与当前单词的匹配位数 
		if(x!=0){   //匹配位数不为0就继续进行下一次的单词搜索 
			mark=true;
			length+=(len[i]-x);  //当前长度增加 
			vis[i]+=1;    //当期单词用过一个加一 
			
			dfs(i,length);
			//上一步递归不符合题意返回至此,长度减去不符合题意的单词,单词的使用次数减一,继续选择单词 
			length-=(len[i]-x);
			vis[i]-=1;
		}
	}
	if(mark==false){     //如果已经找不到单词,比较之前已经得到过的答案选择最长的单词数 
		ans=max(ans,length);
	}
}
int main(){
	int i;
	char l1;
	cin>>t;
	for(i=0;i<t;i++){
		cin>>s[i].lin;
		len[i]=strlen(s[i].lin);
	}
	cin>>l1;
	ans=0;
	for(i=0;i<t;i++)if(s[i].lin[0]==l1){
		memset(vis,0,sizeof(vis));  //初始化单词标记数组 
		vis[i]++; //次单词使用一次 
		dfs(i,len[i]);//当期使用的单词下标与长度 
	}
	cout<<ans;//输出结果 
	return 0;
}

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值