NOIP2002提高组T2:字符串变换

news2024/11/26 8:53:49

题目链接

字符串变换

题目描述

已知有两个字串 A , B A,B A,B,及一组字串变换的规则(至多 6 6 6个规则):
A 1 → B 1 A_1→B_1 A1B1
A 2 → B 2 A_2→B_2 A2B2

规则的含义为:在 A A A中的子串 A 1 A_1 A1 可以变换为 B 1 B_1 B1 A 2 A_2 A2可以变换为 B 2 B_2 B2…。

例如: A = A= A=abcd B = B= B=xyz

变换规则为:

abcxuudyyyz

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

abcdxudxyxyz

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

注意,一次变换只能变换一个子串,例如 A = A= A=aa B = B= B=bb

变换规则为:

ab

此时,不能将两个 a 在一步中全部转换为 b,而应当分两步完成。

输入格式

A    B A~~B A  B
A 1   B 1 A_1~B_1 A1 B1
A 2   B 2 A_2~B_2 A2 B2
… …

第一行是两个给定的字符串 A A A B B B

接下来若干行,每行描述一组字串变换的规则。

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

输出格式

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

输入样例

abcd xyz
abc xu
ud y
y yz

输出样例

3

算法思想

根据题目描述,通过输入的规则将字串 A A A变换为 B B B,求最小步数,显然可以通过BFS求解。

朴素版广搜

分析数据范围,至多 6 6 6个规则,在 10 10 10 步(包含 10 10 10步)以内进行转换,如果直接进行BFS,在最坏情况下搜索的状态空间大约是 6 10 = 60 , 466 , 176 6^{10}=60,466,176 610=60,466,176,可以满足题目要求。

算法实现

  • 将起始字符串 A \text{A} A加入队列
  • 只要队列不空,重复下面的处理:
    • 从队首取出一个字符串 s \text{s} s
    • 如果变换到 s \text{s} s的步数超过 10 10 10,则无解,并结束搜索
    • 1 ∼ n 1\sim n 1n枚举变换规则 a i → b i a_i\rightarrow b_i aibi
      • 只要字符串 s \text{s} s中包含 a i a_i ai
        • 将其替换为 b i b_i bi,得到替换之后的字符串 t \text{t} t
        • 如果替换后等于字符串 B \text{B} B,则搜索结束,返回变换步数
        • 如果字符串 t \text{t} t之前没有出现过,将其加入队列
        • 从下一个位置继续查找 a i a_i ai

代码实现

#include <iostream>
#include <queue>
#include <unordered_map>
using namespace std;
const int N = 7;
string a[N], b[N];
string A, B;
int n;
int bfs()
{
    unordered_map<string, int> dis; //记录搜到到字符串的最小步数
    queue<string> q;
    dis[A] = 0;
    q.push(A);
    int ans = 0;
    while(q.size())
    {
        string s = q.front(); q.pop();
        if(dis[s] >= 10) { return -1; } //超过10步,返回-1
        for(int i = 0; i < n; i ++) //枚举变换规则
        {
            int idx = s.find(a[i]);
            while(idx != -1) //s中存在a[i],可以变换
            {
                string t = s;
                t.replace(idx, a[i].size(), b[i]);
                if(t == B) return dis[s] + 1; //变换到B,返回变换步数
                if(!dis.count(t)) //第一次变换到t
                {
                    dis[t] = dis[s] + 1;
                    q.push(t);
                }
                idx = s.find(a[i], idx + 1); //从下一个位置继续查找a[i]进行替换
            }
        }
    }
    return -1;
}
int main()
{
    cin >> A >> B;
    while(cin >> a[n] >> b[n]) n ++;
    int ans = bfs();
    if(ans == -1) puts("NO ANSWER!");
    else cout << ans;
    return 0;
}

双向广搜

朴素版广搜虽然可以满足题目要求,但是要搜索的状态空间大约是 6 10 = 60 , 466 , 176 6^{10}=60,466,176 610=60,466,176,时间复杂度太高,可以使用双向广搜进行优化。

双向广搜,是指从起点和终点同时开始进行BFS,双向奔赴直到找到共同的目标为止。

使用双向广搜可以把搜索空间降到 2 × 6 5 2\times 6^5 2×65,大大减少了要搜索的状态,剪枝效果明显。

使用双向广搜时要注意:

  • 在双向广搜时,优先选择队列中状态数量较少的方向来扩展,可以优化搜索效率
  • 在扩展时,需要将一层的所有节点扩展完,不能只扩展一个点。如下图所示,第 2 2 2层有 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4四个节点,则需要把这 4 4 4个节点从队列中全部取出进行扩展。否则,找到的可能不是最少的转换次数。
    在这里插入图片描述

代码实现

#include <iostream>
#include <queue>
#include <cstring>
#include <unordered_map>
using namespace std;
const int N = 6;
int n;
string A, B; //起点和终点
string a[N], b[N]; //变换规则
//从队列q中,将同层的节点全部扩展
int extend(queue<string>& q, unordered_map<string, int>& da, unordered_map<string, int>& db, 
    string a[N], string b[N])
{
    int d = da[q.front()]; //层数
    while(q.size() && da[q.front()] == d) //将同层的节点全部扩展
    {
        string s = q.front(); q.pop();
        for(int i = 0; i < n; i ++) //枚举在原字符串中使用替换规则
        {
            int idx = s.find(a[i]);
            while(idx != -1) //s中存在a[i]
            {
                string t = s;
                t.replace(idx, a[i].size(), b[i]);
                if(db.count(t)) return da[s] + db[t] + 1;//如果反方向已经搜索到该字符串t,则搜索结束,返回步数
                if(!da.count(t)) { da[t] = da[s] + 1; q.push(t);} //第一搜索到t
                idx = s.find(a[i], idx + 1); //从下一个位置继续查找a[i]进行替换
            }
        }
    }
    return 11;
}
int bfs()
{
    if(A == B) return 0;
    //双向搜索,扩展时分别进入不同队列
    queue<string> qa, qb;
    //da、db分别存储变换后的字符串到起点A和终点B的转换次数
    unordered_map<string, int> da, db;
    qa.push(A), qb.push(B); //起点和终点插入队列
    da[A] = db[B] = 0;
    int step = 0; //转换次数
    while(qa.size() && qb.size()) //两个队列都不为空
    {
        int t;
        if(qa.size() < qb.size()) //优先搜索状态数较少的方向
            t = extend(qa, da, db, a, b);
        else
            t = extend(qb, db, da, b, a);
        if(t <= 10) return t;
        if(++ step == 10) return -1; //变换10次没有结果
    }
    return -1;
}
int main()
{
    cin >> A >> B;
    while(cin >> a[n] >> b[n]) n ++;
    int t = bfs();
    if(t == -1) puts("NO ANSWER!");
    else cout << t << '\n';
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1493074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024关于idea激活码报This license xxxx has been suspended

HOSTS文件中增加 0.0.0.0 www.jetbrains.com 0.0.0.0 account.jetbrains.com 然后

App原生开发:iOS和Android平台的比较(看这一篇就够了)

引言 移动应用的发展在过去几年里取得了巨大的突破&#xff0c;而原生开发作为构建高性能、富有交互性的应用程序的首选方法&#xff0c;一直占据着重要的地位。在这篇文章中&#xff0c;我们将探讨原生开发在两个主流移动平台——iOS和Android上的关键概念和技术。 概念和重…

JSP语言基础(案例代码)

JSP基本语法 编写一个JSP页面&#xff0c;在该页面中显示当前时间 <% page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-8" import"java.util.*"%> <% page import"java.text.SimpleDateF…

ECMAScript6

课程链接 目录 相关介绍什么是ECMA什么是ECMAScript为什么学习ES6 letconst变量解构赋值模板字符串对象简化写法箭头函数函数参数的默认值rest参数扩展运算符Symbol迭代器生成器函数与调用Promise介绍与基本用法Promise封装读取文件Promise.prototype...then方法Promise.catch…

javascript中的强制类型转换和自动类型转换

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;前端泛海 景天的主页&#xff1a;景天科技苑 文章目录 1.转换函数2.强制类型转换&#xff08;1&#xff09;Number类型强转&…

数字社交时代的引领者:Facebook的元宇宙探索

引言&#xff1a; 在当今数字社交时代&#xff0c;人们的社交方式正在经历着翻天覆地的变化。随着虚拟现实技术的不断发展和元宇宙概念的崛起&#xff0c;社交网络正朝着一个全新的未来迈进。作为全球最大的社交网络平台之一&#xff0c;Facebook正在积极探索元宇宙时代的社交…

串联谐振电路基础知识1

电路图 公式 IU/Zin,其中ZinXLXCR XC&#xff1a;表示为容抗 XL&#xff1a;表示为感抗 R&#xff1a;表示为电阻阻值 特性 电感对越是高频的电流的阻力就会越大&#xff0c;对越是低频的电流的阻力就会越小&#xff0c;感抗的大小是与频率是息息相关的&#xff0c;并且可简单…

Spring事务管理与模板对象

1.事务管理 1.事务回顾 事务指数据库中多个操作合并在一起形成的操作序列 事务的作用 当数据库操作序列中个别操作失败时&#xff0c;提供一种方式使数据库状态恢复到正常状态&#xff08;A&#xff09;&#xff0c;保障数据库即使在异常状态下仍能保持数据一致性&#xff…

时钟显示 html JavaScript

sf.html <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>时间</title><script>function showTime(){var timenew Date();var datetime.getDate();var yeartime.getFullYear();var monthtime.getMonth()1;var …

DataGrip 连接 Centos MySql失败

首先检查Mysql是否运行&#xff1a; systemctl status mysqld &#xff0c; 如果显示没有启动则需要启动mysql 检查防火墙是否打开&#xff0c;是否打开3306的端口 sudo firewall-cmd --list-all 如果下面3306没有打开则打开3306端口 publictarget: defaulticmp-block-inver…

推荐书籍《低代码平台开发实践:基于React》—— 提升开发效率,构建优质应用

写在前面 随着数字化转型的深入&#xff0c;企业对应用开发效率和灵活性的要求不断提高。低代码平台作为新兴的软件开发方式&#xff0c;通过可视化界面和预构建组件&#xff0c;极大简化了应用开发流程&#xff0c;降低了技术门槛。基于React的低代码平台以其组件化、响应式和…

解决MySQL 5.7在Redhat 9中启动报错:libncurses.so.5和libtinfo.so.5缺失问题

在使用Linux系统搭建MySQL数据库的过程中&#xff0c;我们往往会遇到各种依赖库的问题&#xff0c;尤其是在安装较旧版本的MySQL时。最近&#xff0c;在RedHat 9&#xff08;rocky linux 9&#xff09;系统上安装MySQL 5.7版本时&#xff0c;我遇到了一个典型的依赖库缺失错误&…

动态规划(算法竞赛、蓝桥杯)--状态压缩DP蒙德里安的梦想

1、B站视频链接&#xff1a;E31 状态压缩DP 蒙德里安的梦想_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; const int N12,M1<<N; bool st[N];//st[i]存储合并列的状态i是否合法 long long f[N][M];//f[i][j]表示摆放第i列&#xff0c;状态为…

常用“树”数据结构

哈夫曼树 在许多应用中&#xff0c;树中结点常常被赋予一个表示某种意义的数值&#xff0c;称为该结点的权。从树的根到任意结点的路径长度(经过的边数)与该结点上权值的乘积&#xff0c;称为该结点的带权路径长度。树中所有叶结点的带权路径长度之和称为该树的带权路径长度&am…

有没有无损格式转换mp3的方法?

随着数字音乐的发展&#xff0c;无损音乐格式如FLAC、APE、WAV等越来越受到音乐爱好者的青睐。无损音乐保证了音乐在传输和存储过程中不损失任何原始信息&#xff0c;从而保留了音乐的原汁原味。但有时&#xff0c;出于设备兼容性、空间节省或其他原因&#xff0c;我们可能需要…

C语言项目实战——贪吃蛇

C语言实现贪吃蛇 前言一、 游戏背景二、游戏效果演示三、课程目标四、项目定位五、技术要点六、Win32 API介绍6.1 Win32 API6.2 控制台程序6.3 控制台屏幕上的坐标COORD6.4 GetStdHandle6.5 GetConsoleCursorInfo6.5.1 CONSOLE_CURSOR_INFO 6.6 SetConsoleCursorInfo6.7 SetCon…

Ubuntu/Linux系统下Redis的基本操作命令

版本查询 redis-server --version # 或者redis-server -v 如上图所示&#xff0c;redis-server的版本为6.0.9,证明redis已经安装完成。 启动Redis服务 启动命令如下&#xff1a; redis-server启动成功如下所示&#xff1a; 启动过程中遇到如下问题时&#xff0c;杀死指定端…

Python Web开发记录 Day6:MySQL(关系型数据库)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 六、MySQL1、MySQL-概述和引入①MySQL是什么&am…

阿里云几核服务器够用?内存多少合适?

阿里云服务器配置怎么选择&#xff1f;CPU内存、公网带宽和系统盘怎么选择&#xff1f;个人开发者或中小企业选择轻量应用服务器、ECS经济型e实例&#xff0c;企业用户选择ECS通用算力型u1云服务器、ECS计算型c7、通用型g7云服务器&#xff0c;阿里云服务器网aliyunfuwuqi.com整…

【论文精读】Mask R-CNN

摘要 基于Faster RCNN&#xff0c;做出如下改变&#xff1a; 添加了用于预测每个感兴趣区域(RoI)上的分割掩码分支&#xff0c;与用于分类和边界框回归的分支并行。mask分支是一个应用于每个RoI的FCN&#xff0c;以像素到像素的方式预测分割掩码&#xff0c;只增加了很小的计…