数字接龙(蓝桥杯)

news2024/12/27 13:11:46

文章目录

  • 数字接龙
    • 【问题描述】
    • 解题思路
    • DFS

数字接龙

【问题描述】

小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为N × N 的格子棋盘上展开,其中每一个格子处都有着一个 0 . . . K − 1 之间的整数。游戏规则如下:

  1. 从左上角 (0, 0) 处出发,目标是到达右下角 (N − 1, N − 1) 处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。
  2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足:0, 1, 2, . . . , K − 1, 0, 1, 2, . . . , K − 1, 0, 1, 2 . . . 。
  3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。
  4. 路径中不可以出现交叉的线路。例如之前有从 (0, 0) 移动到 (1, 1),那么再从 (1, 0) 移动到 (0, 1) 线路就会交叉。

为了方便表示,我们对可以行进的所有八个方向进行了数字编号,如下图2 所示;因此行进路径可以用一个包含 0 . . . 7 之间的数字字符串表示,如下图 1是一个迷宫示例,它所对应的答案就是:41255214。
在这里插入图片描述

现在请你帮小蓝规划出一条行进路径并将其输出。如果有多条路径,输出字典序最小的那一个;如果不存在任何一条路径,则输出 −1。

【输入格式】
第一行包含两个整数 N、K。
接下来输入 N 行,每行 N 个整数表示棋盘格子上的数字。
【输出格式】
输出一行表示答案。如果存在答案输出路径,否则输出 −1。
【样例输入】

3 3
0 2 0
1 1 1
2 0 2

【样例输出】

41255214

【样例说明】
行进路径如图 1 所示。
【评测用例规模与约定】
对于 80% 的评测用例:1 ≤ N ≤ 5。
对于 100% 的评测用例:1 ≤ N ≤ 10,1 ≤ K ≤ 10。

解题思路

题目分析:

  1. 从左上角 (0, 0) 处出发,目标是到达右下角 (N − 1, N − 1) 处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。
  2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足:0, 1, 2, . . . , K − 1, 0, 1, 2, . . . , K − 1, 0, 1, 2 . . . 。
  3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。
  4. 如果有多条路径,输出字典序最小的那一个
  5. 路径中不可以出现交叉的线路。例如之前有从 (0, 0) 移动到 (1, 1),那么再从 (1, 0) 移动到 (0, 1) 线路就会交叉。

解题思路:

  1. 因为题目的数据范围较小,所以可以使用DFS,移动方向为8个方向
int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};
  1. 我们需要保证遍历顺序为0, 1, 2, . . . , K − 1, 0, 1, 2, . . . , K − 1, 0, 1, 2 . . .
g[x][y] == k - 1 && g[tx][ty] == 0) || g[tx][ty] == g[x][y] + 1

g[x][y] == k - 1 && g[tx][ty] == 0 || g[tx][ty] == g[x][y] + 1:这是一个复合条件,用于检查当前格子 (x, y) 的值与目标格子 (tx, ty) 的值之间的关系是否满足游戏规则。具体来说:

  • g[x][y] == k - 1 && g[tx][ty] == 0:如果当前格子的值等于 k - 1(即棋盘上数字的最大值),则目标格子的值必须为 0,这样才能保证数字序列的循环性。
  • ||:逻辑或操作符,用于连接上述条件和下面的条件。两者满足一个即可
  • g[tx][ty] == g[x][y] + 1:如果当前格子的值不是 k - 1,则目标格子的值必须比当前格子的值大 1,这样才能保证数字序列是递增的。
  1. 设置一个cnt,如果cnt=n*n说明遍历了每个位置
  2. 在遍历8个方向时我们按0、1、2、3、4、5、6、7的顺序遍历就能得到最小字典序,并且用path数组保存,就能把路径输出
  3. 只有走对角线才会发生相交,我们设置一个st数组存储到达每个格子的方向,再进行判断
    在这里插入图片描述
if (i == 1 && (st[x - 1][y] == 3 || st[x][y + 1] == 7))
    continue; // 从当前格子向右移动,检查是否与之前的路径交叉
if (i == 3 && (st[x + 1][y] == 1 || st[x][y + 1] == 5))
    continue; // 从当前格子向下移动,检查是否与之前的路径交叉
if (i == 5 && (st[x][y - 1] == 3 || st[x + 1][y] == 7))
    continue; // 从当前格子向左下移动,检查是否与之前的路径交叉
if (i == 7 && (st[x][y - 1] == 1 || st[x - 1][y] == 5))
    continue; // 从当前格子向左上移动,检查是否与之前的路径交叉

DFS

这段代码是一个基于深度优先搜索(DFS)的算法,用于解决一个特定的路径问题,其中需要考虑路径的字典序。下面是对代码的详细注释:

#include<bits/stdc++.h> // 引入整个标准库和C++ STL库
using namespace std; // 使用标准命名空间

int g[11][11]; // 棋盘,存储每个格子的数字
int d[11][11]; // 访问标记,表示当前格子是否已访问
int st[11][11]; // 状态数组,存储到达每个格子的方向
vector<int> path; // 存储最终的路径

// 移动方向的偏移量,dx 和 dy 分别表示 x 和 y 轴上的偏移
int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};

int n, k; // n 是棋盘的大小,k 是棋盘上数字的最大值

bool dfs(int x, int y, int cnt) { // 深度优先搜索函数
    if (x == n - 1 && y == n - 1 && cnt == n * n) // 如果到达棋盘底部的最后一个格子,并且格子数量符合,返回 true
        return true;
    for (int i = 0; i < 8; i++) { // 遍历所有八个方向
        int tx = x + dx[i]; // 计算目标x坐标
        int ty = y + dy[i]; // 计算目标y坐标
        // 检查目标位置是否在棋盘内,未被访问,并且满足数字序列条件
        if (tx >= 0 && tx < n && ty >= 0 && ty < n && d[tx][ty] == 0 &&
            ((g[x][y] == k - 1 && g[tx][ty] == 0) || g[tx][ty] == g[x][y] + 1)) {
            // 检查当前方向是否会导致路径交叉
            if (i == 1 && (st[x - 1][y] == 3 || st[x][y + 1] == 7))
                continue; // 从当前格子向右移动,检查是否与之前的路径交叉
            if (i == 3 && (st[x + 1][y] == 1 || st[x][y + 1] == 5))
                continue; // 从当前格子向下移动,检查是否与之前的路径交叉
            if (i == 5 && (st[x][y - 1] == 3 || st[x + 1][y] == 7))
                continue; // 从当前格子向左下移动,检查是否与之前的路径交叉
            if (i == 7 && (st[x][y - 1] == 1 || st[x - 1][y] == 5))
                continue; // 从当前格子向左上移动,检查是否与之前的路径交叉
            st[x][y] = i; // 记录当前格子的方向
            d[tx][ty] = 1; // 标记目标格子为已访问
            path.push_back(i); // 将方向编号添加到路径中
            if (dfs(tx, ty, cnt + 1)) // 递归搜索下一个位置
                return true; // 如果找到路径,则返回 true
            path.pop_back(); // 回溯,移除路径中的最后一个方向编号
            d[tx][ty] = 0; // 回溯,重置目标格子的访问标记
            st[x][y] = -1; // 回溯,重置当前格子的方向
        }
    }
    return false; // 如果所有方向都不是解决方案,则返回 false
}

int main() {
    cin >> n >> k; // 读取棋盘大小和数字的最大值
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> g[i][j]; // 填充棋盘
        }
    }
    // 检查棋盘右下角的数字是否为 k-1,如果不是,则无法形成合法路径,输出-1
    if (g[n - 1][n - 1] != k - 1) {
        cout << -1;
        return 0;
    }
    memset(st, -1, sizeof st); // 初始化状态数组,所有值设为 -1
    d[0][0] = 1; // 标记起始格子为已访问
    if (dfs(0, 0, 1)) { // 从(0, 0)开始深度优先搜索
        for (auto i : path) // 输出找到的路径
            cout << i;
    } else {
        cout << -1; // 如果没有找到路径,输出-1
    }
    return 0;
}

这段代码使用了深度优先搜索算法来找到一条合法的路径,它考虑了路径的唯一性和循环序列的要求。代码中还包含了避免路径交叉的逻辑。如果找到了一条合法路径,它会输出该路径的编号序列;如果没有找到,它会输出-1。

注意,代码中 memset(st, -1, sizeof st); 用于初始化 st 数组的所有元素为 -1,表示没有格子被访问过。而 d[0][0] = 1; 则是标记起始格子 (0, 0) 为已访问。path 数组用来存储路径,以便在找到解决方案时输出。

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

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

相关文章

专利基础概念

专利是一种知识产权形式&#xff0c;它为发明创造提供了一种法律保护机制&#xff0c;允许发明者在一定期限内对其发明享有独占权。 1、专利类型 专利类型&#xff0c;也被称为专利的客体&#xff0c;是指符合专利授予条件的各种发明创造。根据中国专利法&#xff0c;发明创造…

【经典小游戏】猜数字

前言1. 游戏介绍2. 游戏实现3. 游戏优化结语 个人主页&#xff1a;C_GUIQU 前言 各位小伙伴大家好&#xff01; 先问大家一个问题&#xff1a;我们为什么要学习&#xff1f; 简单来说&#xff0c;就是为了实践&#xff01;只有不断学习才可以帮助我们更好地实践&#xff01; 小…

【Java网络编程】网络编程中的基本概念及实现UDP、TCP客户端服务器程序

目录 一、什么是网络编程&#xff1f; 二、网络编程中的基本概念 1. 客户端和服务器 2. 请求和响应 三、Socket套接字 UDP数据报套接字编程 1. DatagramSocket 2. DatagramPacket 3. UDP回显客户端服务器程序 4. UDP字典客户端服务器程序 TCP流套接字编程 1. Serve…

【JS】js数字转k、w结尾 | 1000 = 1k

问题 数字转k、w结尾 如&#xff1a;10001k 100001w 码 /*** 数字转k,w* param {Number} num * returns String*/ const numberTokw num > {if (num < 1000) return numlet endStr w,numVal 10000;if (num > 999 && num < 10000) {endStr knumVal …

设计模式之创建型模式详解

设计模式 创建型模式 创建型模式(Creational Pattern)对类的实例化过程进行了抽象&#xff0c;能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰&#xff0c;外界对于这些对象只需要知道它们共同的接口&#xff0c;而不清楚其具体的实现细节&#xff0…

物联网实战--驱动篇之(九)NB-IOT(BC260)

目录 一、NB-IOT简介 二、NB-IOT要素 三、代码详解 四、平台端 一、NB-IOT简介 实际上&#xff0c;就是NB-Iot彻底引爆了物联网的&#xff0c;大概2018年左右&#xff0c;NB推广如火如荼&#xff0c;同时广域网、低功耗的LPWAN网络也逐渐传开&#xff0c;现在回头来看&…

Flyweight 享元

意图 运用共享技术有效地支持大量细粒度的对象。 结构 其中 Flyweight描述一个接口&#xff0c;通过这个接口Flyweight可以接受并作用于外部状态。ConcreteFlyweight实现Flyweight接口&#xff0c;并作为内部状态&#xff08;如果有&#xff09;增加存储空间。ConcreteFlywe…

[Java基础揉碎]集合

目录 集合的理解和好处 数组 集合的理解和好处 继承图 ​编辑 简单实例 Collection接口和常用方法 1) add:添加单个元素 2) remove:删除指定元素 3) contains:查找元素是否存在 4) size:获取元素个数 5) isEmpty:判断是否为空 ​编辑 6) clear:清空 7) addAll:添…

Prior Knowledge-Guided Transformer for Remote Sensing Image Captioning

Prior Knowledge-Guided Transformer for Remote Sensing Image Captioning 1. 摘要 遥感图像(RSI)字幕生成旨在为遥感图像生成有意义且语法正确的句子描述。然而,相比于自然图像字幕,RSI字幕生成面临着由于RSI特性而产生的额外挑战。第一个挑战源于这些图像中存在大量物体。…

ssh-key关于authorized_keys电脑与linux互相认证

思路&#xff1a; 在A上生成公钥私钥。将公钥拷贝给server B&#xff0c;要重命名成authorized_keys(从英文名就知道含义了)Server A向Server B发送一个连接请求。Server B得到Server A的信息后&#xff0c;在authorized_key中查找&#xff0c;如果有相应的用户名和IP&#xf…

冰达ROS机器人快速使用指南

欢迎来到《冰达ROS机器人极简使用指南》 Q&#xff1a;这份教程适合谁&#xff1f; A&#xff1a;适合完全0基础新手&#xff0c;需要快速跑起来机器人的基本功能。也适合技术大佬需要快速的了解冰达ROS机器人的使用方法。 Q&#xff1a;这份教程内容很少&#xff0c;是不是…

路由器热备份

HSRP HSRP&#xff08;Hot Standby Routing Protocol&#xff09;热备份路由选择协议 HSRP是思科私有的协议&#xff0c;HSRP起到一个双网关热备份的一个目的&#xff0c;不考虑线路问题针对设备而言&#xff0c;一个设备挂了还有另外一台设备&#xff0c;所以双网关也叫双机…

动力学重构/微分方程参数拟合 - 基于模型

这一篇文章&#xff0c;主要是给非线性动力学&#xff0c;对微分方程模型参数拟合感兴趣的朋友写的。笼统的来说&#xff0c;这与混沌系统的预测有关&#xff1b;传统的机器学习的模式识别虽然也会谈论预测结果&#xff0c;但他们一般不会涉及连续的预测。这里我们考虑的是&…

URL地址解析至页面展示全过程(面试详细解答)

目录 1、解析URL 2、缓存判断 ​编辑3、DNS解析 ​编辑4、获取MAC地址 5、TCP三次握手 6、HTTP请求 7、服务器处理请求&#xff0c;返回HTTP响应 8、页面渲染 9、TCP四次挥手 10、浏览器解析HTML 11、浏览器布局渲染 1、解析URL 首先会对 URL 进行解析&#xff0c;…

C++_类型转换

文章目录 学习目标&#xff1a;1.static_cast2. reinterpret_cast3.const_cast4. dynamic_cast 学习过程1.static_cast2. reinterpret_cast3.const_cast在这里插入图片描述4. dynamic_cast 学习目标&#xff1a; 标准C为了加强类型转换的可视性&#xff0c;引入了四种命名的强…

黑马程序员Linux简单入门学习笔记

Linux介绍 内核提供系统最核心的功能&#xff0c;如: 调度CPU、调度内存、调度文件系统、调度网络通讯、调度等系统级应用程序&#xff0c;可以理解为出厂自带程序&#xff0c;可供用户快速上手操作系统&#xff0c;如:文件管理器、任务管理器、图片查看、音乐播放等 目录结构 …

在PostgreSQL中如何实现递归查询,例如使用WITH RECURSIVE构建层次结构数据?

文章目录 解决方案使用WITH RECURSIVE进行递归查询示例代码 总结 在PostgreSQL中&#xff0c;递归查询是一种非常强大的工具&#xff0c;它可以用来查询具有层次结构或树形结构的数据。例如&#xff0c;你可能会在员工-经理关系、目录结构或组织结构图中遇到这样的数据。为了处…

*Linux系统的进程和计划任务管理

目录 一、查看进程 1、程序和进程的关系 *2、ps查看静态进程信息 1&#xff09;ps aux 2&#xff09;ps -elf *3、top查看动态进程信息 4、pgrep查看进程信息 5、pstree查看进程树 二、控制进程 1、进程启动方式 2、进程的前后台调度 3、终止进程的运行 三、计划任…

VSCode搭建内核源码阅读开发环境

0. 参考链接 使用VSCode进行linux内核代码阅读和开发_vscode阅读linux内核-CSDN博客 1. 搭建Linux内核源码阅读环境 现状&#xff0c;Linux内核源码比较庞大文件非常多&#xff0c;其中又包含的众多的宏定义开关配置选项&#xff0c;这使得阅读内核源代码称为一件头疼的事。 …

Android AIDL接口

一.AlDI接口简介 AIDL&#xff08;Android Interface Definition Language&#xff09;是一种 IDL 语言&#xff0c;用于生成可以在 Android 设备上两个进程之间进行进程间通信&#xff08;IPC&#xff09;的代码。 通过 AIDL&#xff0c;可以在一个进程中获取另一个进程的数据…