[NOIP2000 提高组] 单词接龙

[NOIP2000 提高组] 单词接龙

题目背景

注意:本题为上古 NOIP 原题,不保证存在靠谱的做法能通过该数据范围下的所有数据。

题目描述

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

输入格式

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

输出格式

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

样例 #1

样例输入 #1

5
at
touch
cheat
choose
tact
a

样例输出 #1

23

提示

样例解释:连成的“龙”为 atoucheatactactouchoose

n ≤ 20 n \le 20 n20


思路:

1.输入数据
2.从n个单词中寻找以字符c开头的单词
3.dfs
 . 如果拼接后的单词长度大于 ans 更新ans
 . 枚举所有单词 
 . 如果能够拼接 返回拼接后的字符串
 . vis 标志位加一
 . dfs
 . 回退vis 标志位
4.输出 ans

Code:(c语言)

c语言没有string类型 写起来比较麻烦 特别是单个字符输入会有问题 建议采用c++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

int n, ans =0, vis[25] = {0};
char str[25][25], c;

bool strcon(char *str1, char *str2){			//判断是否可以连接 如果可以,将连接后的单词返回给str1并返回true 否则返回false 
	int len1 = strlen(str1), len2 = strlen(str2);
	char sub1[1024], sub2[1024];
	memset(sub1, '\0', sizeof(sub1));
	memset(sub2, '\0', sizeof(sub2));				//初始化子串 
	
	int i;
	for(i = 1; i < len1 && i < len2; i++){			//将i个字符的子串进行比较 
		strcpy(sub1, &str1[len1-i]);				//截取子串1 从第len1-1开始 复制 到末尾 
		strncpy(sub2, str2, i);						//截取子串2 从第0个开始 复制 i个 
		if(strcmp(sub1, sub2) == 0){				//相等 
			strcpy(sub2, &str2[i]);
			strcat(str1, sub2);						//接龙 
			return true;
		}
	}
	return false;
} 

void dfs(char *s){					//搜索 
	char temp[1024];				//临时变量 用来存储接龙单词 
	memset(temp, '\0', sizeof(temp));		//初始化为空串 
	strcpy(temp, s);				//复制s给temp 
	
	if(strlen(temp) > ans){			//单词长度大于已经存储的长度就更新长度 
		ans = strlen(temp);
	}
	
	int i;
	for(i = 0; i < n; i++){			//枚举所有单词 
		if(vis[i] == 2) continue;	//已经有两次不再搜索 
		if(strcon(temp, str[i])){	//判断是否能连接 
			vis[i]++;				//标志位加1 
			dfs(temp);				//新的单词继续搜索 
			vis[i]--;				//标志位回退 
			strcpy(temp, s);		//单词回退 
		}
	}
	
}

int main(){
	memset(str, '\0', sizeof(str));
	scanf("%d", &n);
	int i;
	for(i = 0; i < n; i++){
		scanf("%s\n", str[i]);
	}
	scanf("%c", &c);
	
	for(i = 0; i < n; i++){
		if(str[i][0] == c){
			vis[i]++;
			dfs(str[i]);
			vis[i]--;
		}
	}
	
	printf("%d", ans);
	return 0;
}

Code:(c++)

#include <bits/stdc++.h>
using namespace std;

int n, ans =0, vis[25] = {0};
char c;
string str[25];

string strcon(string s1, string s2){
	int len1 = s1.length(), len2 = s2.length();
	for(int i = 1; i < len1 && i < len2; i++){
		if(s1.substr(len1-i, i) == s2.substr(0, i)){		//子串函数 从第一个参数位置截取 第二个参数个字符 
			return s1.substr(0, len1-i) + s2;
		}
	}
	return "0";
}

void dfs(string s){
	if(s.length() > ans){
		ans = s.length();
	}
	
	for(int i = 0; i < n; i++){
		if(vis[i] < 2 && strcon(s, str[i]) != "0"){
			vis[i]++;
			dfs(strcon(s, str[i]));
			vis[i]--;
		}
	}
}

int main(){
	cin >> n;
	for(int i; i < n; i++){
		cin >> str[i];
	}
	cin >> c;
	
	for(int i = 0; i < n; i++){
		if(str[i][0] == c){
			vis[i]++;
			dfs(str[i]);
			vis[i]--;
		}
	}
	
	cout << ans;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时屿.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值