洛谷 P1032 字串变换

文章讲述了如何通过广度优先搜索算法和朴素模式匹配,利用给定的字符串变换规则,计算将字符串A转换为字符串B所需的最少步骤,如果在10步内无法转换则输出NOANSWER!
摘要由CSDN通过智能技术生成

题目描述

已知有两个字串 A,B 及一组字串变换的规则(至多 6 个规则),形如:

  • A1​→B1​。
  • A2​→B2​。

规则的含义为:在 A 中的子串 A1​ 可以变换为 B1​,A2​ 可以变换为 B2​⋯。

例如:A=abcd,B=xyz,

变换规则为:

  • abc→xu,ud→y,y→yz。

则此时,A 可以经过一系列的变换变为 B,其变换的过程为:

  • abcd→xud→xy→xyz。

共进行了 3 次变换,使得 A 变换为 B。

输入格式

第一行有两个字符串 A,B。

接下来若干行,每行有两个字符串 Ai​,Bi​,表示一条变换规则。

输出格式

若在 10 步(包含 10 步)以内能将 A 变换为 B,则输出最少的变换步数;否则输出 NO ANSWER!

输入输出样例

输入 #1

abcd xyz
abc xu
ud y
y yz

输出 #1

3

说明/提示

对于 100% 数据,保证所有字符串长度的上限为 20。

【题目来源】

NOIP 2002 提高组第二题

解题思路

采用广度搜索,字符串匹配采用朴素模式匹配也可以,需要注意的是,主串可能有多个子串匹配成功,在bfs中都需要加入列队(别看只有6个规则,列队数组却比较大,不然RE等你)

AC代码

#include<stdio.h>
#include<string.h>
struct nb {//储存变化规则
	char s[23];//变化前
	char h[23];//变化后
}e[8];
struct linknode {//列队
	char g[23];//串
	int s;//步数
}link[2110000];
int main()
{
	int k = 1;
	char a[23], b[23];
	scanf("%s %s", a, b); //输入起始串和终止串
	while (scanf("%s %s", e[k].s, e[k].h)!=EOF)//输入规则
		k++;
	int hard = 1, tail = 2, flag = 0;
	strcpy(link[1].g, a); link[1].s = 0;//起始串入队
	while (hard < tail && link[hard].s < 10)
	{
		for (int i = 1; i < k; i++)//列举所有变化规则
		{
			int x = 0, y = 0;
			int p = strlen(link[hard].g);
			int q = strlen(e[i].s);
			while (x < p)//继续寻找主串后面是否有匹配的
			{
				while (x < p && y < q)//朴素模式匹配
				{
					if (link[hard].g[x] == e[i].s[y])
					{
						x++; y++;
					}
					else
					{
						x = x - y + 1;
						y = 0;
					}
				}
				if (y == q)//y==q代表匹配成功
				{
					int mm = 0;
					//入队操作
					for (int j = 0; j < x - y; j++)
						link[tail].g[mm++] = link[hard].g[j];
					int hj = strlen(e[i].h);
					for (int j = 0; j < hj; j++)
						link[tail].g[mm++] = e[i].h[j];
					for (int j = x; j < p; j++)
						link[tail].g[mm++] = link[hard].g[j];
					link[tail].g[mm] = '\0'; link[tail].s = link[hard].s + 1;
					if (strcmp(link[tail].g, b) == 0)//如果找到终点串结束
					{
						flag = 1;
						break;
					}
					tail++;
				}
				y = 0;
			}
			if (flag == 1)
				break;
		}
		if (flag == 1)
			break;
		hard++;//一个点广搜结束进行下一个
	}
	if (flag == 1)//找到终点串
	{
		if (link[tail].s <= 10)
			printf("%d", link[tail].s);
		else
			printf("NO ANSWER!");
	}
	else//没找到终点串
		printf("NO ANSWER!");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

3分人生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值