洛谷 P1032 [NOIP2002 T2] 字串变换

59 篇文章 0 订阅
40 篇文章 0 订阅

题目描述

已知有两个字串 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’

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

输入输出格式

输入格式:

键盘输人文件名。文件格式如下:

A B A1 B1 \

   A2 B2 |-> 变换规则

... ... /

所有字符串长度的上限为 20。

输出格式:

输出至屏幕。格式如下:

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

输入输出样例

输入样例#1:
abcd xyz
abc xu
ud y
y yz
输出样例#1:
3










~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

bfs+字符串~

刷新世界观的神题……

(1)队列要建成string型的;

(2)map还可以当做记录状态的数组来用;

(3)队列还有find,replace等等神奇的操作;

(4)不定项输入用scanf可能会RE,cin实在强大;

(5)这题是没法在本机调试的,只能在OJ上交后再改错,帮我迅速拉低正确率……

这道题用到了类似bfs的算法。

把目标串和初始串分别加入队列中,每次双向更新并记录可以更新到的字符串以及其改变次数,直到某一队列中更新出另一队列曾更新出的结果,就直接输出,因为此时的解一定是最优的。

(输出结果要-2,因为刚开始为了区分是否更新过,初始两串都记为度1。)


#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
using namespace std;

int n,len;
queue<string> qa,qb;
string a,b,s1[21],s2[21];
map<string,int> ba,bb;

int main()
{
	cin>>a>>b;n=1;
	while(cin>>s1[n]>>s2[n]) n++;n--;
	ba[a]=1;bb[b]=1;qa.push(a);qb.push(b);
	while(1)
	{
		if(qa.empty() || qb.empty())
		{
			printf("NO ANSWER!\n");return 0;
		}
		string nowa=qa.front(),nowb=qb.front();
		for(int i=1;i<=n;i++)
		{
			int kkz=0;
			while((kkz=nowa.find(s1[i],kkz))!=-1)
			{
				len=s1[i].size();
				nowa.replace(kkz,len,s2[i]);
				if(!ba[nowa])
				{
					ba[nowa]=ba[qa.front()]+1;qa.push(nowa);
				}
				if(bb[nowa])
				{
					printf("%d\n",ba[nowa]+bb[nowa]-2);return 0;
				}
				kkz++;
				nowa=qa.front();
			}
			kkz=0;
			while((kkz=nowb.find(s2[i],kkz))!=-1)
			{
				len=s2[i].size();
				nowb.replace(kkz,len,s1[i]);
				if(!bb[nowb])
				{
					bb[nowb]=bb[qb.front()]+1;qb.push(nowb);
				}
				if(ba[nowb])
				{
					printf("%d\n",bb[nowb]+ba[nowb]-2);return 0;
				}
				kkz++;
				nowb=qb.front();
			}
		}
		qa.pop();qb.pop();
	}
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值