一道看似非常水的题

  大意 :将一个字串 经过几种变换规则变为给定的另一个子串 ,求最小操作数。

  code[vs] 传送门

  洛谷传送门

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

  

  思路:从前从后双向BFS 不加限制 若递归次数等于10次仍未找到答案时,输出NO ANSWER 。其他的若替换完后 从 前端BFS的串 在从后端BFS出现过,则此时递归次数乘2减一即为答案,   从后端BFS的情况同上。   具体实现,就按照题意来,依次扫描变换规则,进行替换,替换完的字串加入队列。

  双向BFS

#include <iostream>
#include <cstring>
#include <map>
#include <cstdio>
using namespace std;
const int Max = ;
string A, B;
string s_change [][], Front[Max], Back[Max];
int Limit = , head_Front = , tail_Front = , tail_Back = , head_Back = , tot = ;
map < string , int > Map_Front;
map < string , int > Map_Back;
void BFS ()
{
tot++; //记录递归次数
string s, s_replace; // s是 变换后的字串 ,s_replace 是当前需变换的字串
int head, tail;
head = head_Front; //调整指针
tail = tail_Front;
for (int i = head; i <= tail; i++)
for (int j = ; j <= Limit; j++) //变换种数 ,变为不同的替换规则
{
int change_Front = ;
while (change_Front != -) //每个字串中可以替换的字串不止一个
{
s_replace = Front [i]; //取出当前需被变换的字串
change_Front = s_replace.find (s_change [j][], change_Front ); //查找变换规则 ,change_Front是 当前规则 出现的位置
if (change_Front >= )
{
s = s_replace.replace (change_Front, s_change [j][].length(), s_change [j][]); //进行替换, s存的是替换完的字串
if (Map_Front [s] == ) //剪枝 ,若该字串出现过,则不进入队列
{
if (Map_Back [s] != ) //如果能在中间遇到,就直接输出答案
{
cout << tot * - ;
return ;
}
Front [++tail_Front] = s; //加入队列
Map_Front [s] = ; //标记为出现过
}
}
if (change_Front != -) change_Front += s_change[j][].length(); //寻找下一个字串
}
}
head_Front = tail + ; //同上 ,不过是从后面进行BFS
head = head_Back;
tail = tail_Back;
for (int i = head; i <= tail; ++i)
for (int j = ; j <= Limit; ++j)
{
int change_Back = ;
while (change_Back != -)
{
s_replace = Back[i];
change_Back = s_replace.find (s_change[j][], change_Back);
if (change_Back >= )
{
s = s_replace.replace (change_Back, s_change [j][].length(), s_change[j][]);
if (Map_Back[s] == )
{
if(Map_Front[s] != )
{
cout << tot * ;
return ;
}
Back[++tail_Back] = s;
Map_Back[s] = ;
}
}
if (change_Back != -) change_Back = change_Back + s_change [j][].length();
}
}
head_Back = tail + ;
if (tot == ) //以十次为限,若十次后仍未找到,则输出NO ANSWER
{
cout << "NO ANSWER!";
return;
}
BFS ();
}
int main()
{
ios::sync_with_stdio (false);
cin >> A >> B;
while (cin >> s_change[Limit][] >> s_change [Limit][]) Limit++;
Limit--; // 替换的组数
Map_Front [A] = ; //用 map 记录
Map_Back [B] = ;
Front [] = A; //加入队列
Back [] = B;
BFS ();
return ;
}

  注意:此题属于那种看似很水,但是实现有难度的题。。

字串变换 (2002 年NOIP全国联赛提高组)的更多相关文章

  1. 1099 字串变换 2002年NOIP全国联赛提高组

    1099 字串变换 2002年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 已知有 ...

  2. codevs 1098 均分纸牌 2002年NOIP全国联赛提高组 x

     时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold   题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必 ...

  3. 1009 产生数 2002年NOIP全国联赛普及组

    1009 产生数 2002年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold   题目描述 Description 给出一个整数 n(n< ...

  4. Codevs 1010 过河卒 2002年NOIP全国联赛普及组

    1010 过河卒 2002年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 传送门 题目描述 Description 如图,A 点有一个过河卒 ...

  5. 1008 选数 2002年NOIP全国联赛普及组

    1008 选数 2002年NOIP全国联赛普及组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description ...

  6. 1010 过河卒 2002年NOIP全国联赛普及组codevs

    1010 过河卒  2002年NOIP全国联赛普及组codevs 题目描述 Description 如图,A 点有一个过河卒,需要走到目标 B 点.卒行走规则:可以向下.或者向右.同时在棋盘上的任一点 ...

  7. Codevs 1171 潜伏者 2009年NOIP全国联赛提高组

    1171 潜伏者 2009年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description [问题描述] R 国和S 国正陷 ...

  8. 1154 能量项链 2006年NOIP全国联赛提高组 codevs

    1154 能量项链  2006年NOIP全国联赛提高组 codevs 题目描述 Description 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头 ...

  9. 过河 2005年NOIP全国联赛提高组(离散化+dp)

    1105 过河 2005年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description 在河上有一 ...

随机推荐

  1. 使用brew安装软件

    使用brew安装软件 brew 又叫Homebrew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件, 只需要一个命令, 非常方便 brew类似ubuntu系统下的apt- ...

  2. Nginx安装配置与HelloWorld

    <深入理解Nginx>阅读与实践(一):Nginx安装配置与HelloWorld 最近在读陶辉的<深入理解Nginx:模块开发与架构解析>,一是想跟着大牛练练阅读和编写开源代码 ...

  3. Javascript:再论Javascript的单线程机制 之 DOM渲染时机

    Javascript:再论Javascript的单线程机制 之 DOM渲染时机 背景 Javascript是单线程事件驱动的,所有能看到的Javascript代码都是在一个线程执行,定时器回调和AJA ...

  4. elasticsearch data importing

    ElasticSearch stores each piece of data in a document. That's what I need. Using the bulk API. Trans ...

  5. C++中#和##的特殊使用

    1.用#号将输入的内容转换为字符串. 用##号将两个参数合并. #include <iostream> using namespace std; //将输入的内容转换成字符串 #defin ...

  6. 第一章 引言--《设计模式-可复用面向对象软件的基础》Erich Gamma

    第一章 引言 本章主要是让我们大致明白设计模式是干嘛用的,模式分类,设计模式如何解决设计问题以及几种常见的面向对象设计中软件的复用方法. 1.什么是设计模式? 个人理解概括,设计模式是对一类问题的抽象 ...

  7. php的curl封装类

    之前一直做爬虫相关的,每次自己去写一系列curl_setopt()函数太繁琐,我于是封装了如下curl请求类. <?php /** * @author freephp * @date 2015- ...

  8. java基础知识拾遗(三)

    1.类加载 bootstrap classloader -引导(也称为原始)类加载器,它负责加载Java的核心类. extension classloader -扩展类加载器,它负责加载JRE的扩展目 ...

  9. 【Zookeeper】源码之序列化

    一.前言 在完成了前面的理论学习后,现在可以从源码角度来解析Zookeeper的细节,首先笔者想从序列化入手,因为在网络通信.数据存储中都用到了序列化,下面开始分析. 二.序列化 序列化主要在zook ...

  10. C语言之形参和实参

    一 形参与实参 1).定义 形参:形式参数. 就是定义函数的时候,写在函数名小括号后面的参数叫形参 实参:实际参数. 就是调用函数的时候,调用函数时写在函数名小括号后面的参数就叫实参 2).注意项 a ...