洛谷刷题日记||基础篇8

news2024/11/18 17:22:14

#include <iostream>
#include <vector>
using namespace std;

int N, M; // N为行数,M为列数
vector<vector<char>> field; // 表示田地的网格,每个元素是'W'或'.'
vector<vector<bool>> visited; // 用来记录网格是否访问过,防止重复计算

// 定义8个方向的偏移量,用于DFS时遍历相邻格子
int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1}; // 行方向的变化量
int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1}; // 列方向的变化量

// 深度优先搜索函数,用于从一个起点探索整个水坑
void dfs(int x, int y) {
    // 标记当前位置为已访问
    visited[x][y] = true;
    // 遍历8个相邻方向
    for (int i = 0; i < 8; i++) {
        int nx = x + dx[i]; // 计算新位置的行号
        int ny = y + dy[i]; // 计算新位置的列号
        // 判断新位置是否有效:在边界内,未被访问过,且是水格子
        if (nx >= 0 && nx < N && ny >= 0 && ny < M && !visited[nx][ny] && field[nx][ny] == 'W') {
            dfs(nx, ny); // 递归访问新位置
        }
    }
}

int main() {
    cin >> N >> M; // 读取网格的行数和列数
    field.resize(N, vector<char>(M)); // 初始化网格
    visited.resize(N, vector<bool>(M, false)); // 初始化访问标记数组为false
    
    // 输入田地网格数据
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> field[i][j]; // 读取每个格子的值('W' 或 '.')
        }
    }
    
    int pondCount = 0; // 统计水坑的数量
    // 遍历田地中的每个格子
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            // 如果当前格子是水,且未被访问过,则启动一次DFS
            if (!visited[i][j] && field[i][j] == 'W') {
                dfs(i, j); // 使用DFS探索整个连通水坑
                pondCount++; // 每次启动DFS,说明发现了一个新的水坑
            }
        }
    }
    
    // 输出水坑的数量
    cout << pondCount << endl;
    return 0;
}


 

 

#include <iostream>
#include <vector>
#include <string>
using namespace std;

// 定义方向数组 directions,共 8 个方向
// 分别是:右、下、左、上、右下、左下、右上、左上
const int directions[8][2] = {
    {0, 1}, {1, 0}, {0, -1}, {-1, 0}, // 水平和垂直方向
    {1, 1}, {1, -1}, {-1, 1}, {-1, -1} // 对角线方向
};

// 检查坐标 (x, y) 是否在矩阵范围内
// x 和 y 都必须在 [0, n) 范围内才是有效位置
bool isValid(int x, int y, int n) {
    return x >= 0 && x < n && y >= 0 && y < n;
}

// 在从 (x, y) 开始、沿 (dx, dy) 方向,寻找是否存在目标单词 word
// 如果找到完整的单词,将路径标记在 visited 矩阵中
bool findWord(vector<string>& matrix, vector<vector<bool>>& visited, int x, int y, int dx, int dy, const string& word) {
    int n = matrix.size(); // 获取矩阵的大小
    // 遍历目标单词的每个字符
    for (int i = 0; i < word.size(); i++) {
        int nx = x + i * dx; // 根据方向计算目标字符的行坐标
        int ny = y + i * dy; // 根据方向计算目标字符的列坐标
        // 检查是否越界或字符不匹配
        if (!isValid(nx, ny, n) || matrix[nx][ny] != word[i]) {
            return false; // 如果任意一个字符不符合,返回 false
        }
    }
    // 如果找到完整的单词,将路径标记为 true
    for (int i = 0; i < word.size(); i++) {
        int nx = x + i * dx; // 计算路径上的行坐标
        int ny = y + i * dy; // 计算路径上的列坐标
        visited[nx][ny] = true; // 标记该位置属于目标单词路径
    }
    return true; // 返回 true 表示找到了单词
}

int main() {
    int n;
    cin >> n; // 输入矩阵的大小 n
    vector<string> matrix(n); // 定义 n 行字符串组成的矩阵
    for (int i = 0; i < n; i++) {
        cin >> matrix[i]; // 输入矩阵的每一行
    }

    string target = "yizhong"; // 目标单词
    int targetLen = target.length(); // 目标单词的长度
    vector<vector<bool>> visited(n, vector<bool>(n, false)); // 定义标记矩阵,初始化为 false

    // 遍历矩阵中的每个位置,检查是否能找到 "yizhong"
    for (int i = 0; i < n; i++) { // 遍历每一行
        for (int j = 0; j < n; j++) { // 遍历每一列
            if (matrix[i][j] == 'y') { // 只有起点是 'y' 时,才有可能找到单词
                for (auto dir : directions) { // 遍历 8 个方向
                    findWord(matrix, visited, i, j, dir[0], dir[1], target);
                }
            }
        }
    }

    // 构造输出矩阵,根据 visited 矩阵决定输出内容
    for (int i = 0; i < n; i++) { // 遍历每一行
        for (int j = 0; j < n; j++) { // 遍历每一列
            if (!visited[i][j]) { // 如果该位置不在单词路径中
                cout << '*'; // 输出 '*'
            } else { // 如果该位置是单词路径的一部分
                cout << matrix[i][j]; // 输出原字符
            }
        }
        cout << endl; // 输出换行符,切换到下一行
    }

    return 0; // 程序结束,返回 0
}

这段代码的作用是从矩阵中的某个起点 (x, y) 开始,沿指定方向 (dx, dy) 检查能否连续找到目标单词 word。我们逐个字符进行匹配,并确保目标位置有效且字符符合要求。如果任一条件不满足,立即返回 false。下面是对每一部分的详细解释:

 for (int i = 0; i < word.size(); i++) {
        int nx = x + i * dx; // 根据方向计算目标字符的行坐标
        int ny = y + i * dy; // 根据方向计算目标字符的列坐标
        // 检查是否越界或字符不匹配
        if (!isValid(nx, ny, n) || matrix[nx][ny] != word[i]) {
            return false; // 如果任意一个字符不符合,返回 false
        }
    }

小技巧

  1. 减少重复检查:由于 nxny 的计算是基于线性关系的,可以直接在循环中累计结果。
  2. 提前终止:发现不匹配时立刻返回,节约时间。

这段代码的核心是通过数学计算实现精确的方向定位和单词匹配。


 


 

 

逐步解析

逆向思维

标记外部 0
  1. 遍历矩阵边界的每一行和每一列。
    • 如果某个位置是 0 且未访问过,将其加入队列并标记为已访问。
  2. 利用 BFS,检查所有与当前边界 0 连通的其他 0,标记它们为外部 0
填充闭合圈内的 0
  1. 遍历矩阵中的每个格子。
    • 如果某个位置是 0 且未被标记为外部 0(visited[i][j] == false),说明该格子在闭合圈内。
    • 将该格子的值修改为 2
输出结果
  • 遍历矩阵,逐个输出值,格式化输出。

 

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

// 四个方向数组,用于表示上下左右移动的偏移量
const int directions[4][2] = {
    {0, 1},  // 右
    {1, 0},  // 下
    {0, -1}, // 左
    {-1, 0}  // 上
};

// 检查坐标 (x, y) 是否在矩阵范围内
bool isValid(int x, int y, int n) {
    return x >= 0 && x < n && y >= 0 && y < n;
}

// 标记所有与矩阵边界连通的 0
void markOutsideZeroes(vector<vector<int>>& matrix, vector<vector<bool>>& visited) {
    int n = matrix.size();
    queue<pair<int, int>> q; // 队列用于 BFS 遍历

    // 遍历矩阵的四个边界,将边界上的 0 入队
    for (int i = 0; i < n; i++) {
        if (matrix[i][0] == 0 && !visited[i][0]) { // 左边界
            q.push({i, 0});       // 入队
            visited[i][0] = true; // 标记为已访问
        }
        if (matrix[i][n - 1] == 0 && !visited[i][n - 1]) { // 右边界
            q.push({i, n - 1});
            visited[i][n - 1] = true;
        }
    }
    for (int j = 0; j < n; j++) {
        if (matrix[0][j] == 0 && !visited[0][j]) { // 上边界
            q.push({0, j});
            visited[0][j] = true;
        }
        if (matrix[n - 1][j] == 0 && !visited[n - 1][j]) { // 下边界
            q.push({n - 1, j});
            visited[n - 1][j] = true;
        }
    }

    // 使用 BFS 遍历所有与边界连通的 0
    while (!q.empty()) {
        auto [x, y] = q.front(); // 取出队首元素
        q.pop();

        // 遍历当前点的上下左右四个方向
        for (auto dir : directions) {
            int nx = x + dir[0]; // 计算新坐标
            int ny = y + dir[1];
            // 如果新坐标有效且是未访问的 0,则将其入队
            if (isValid(nx, ny, n) && matrix[nx][ny] == 0 && !visited[nx][ny]) {
                visited[nx][ny] = true; // 标记为已访问
                q.push({nx, ny});       // 入队
            }
        }
    }
}

// 将闭合圈内的 0 填充为 2
void fillInnerZeroes(vector<vector<int>>& matrix, const vector<vector<bool>>& visited) {
    int n = matrix.size();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            // 如果当前格子是 0 且未被标记为外部 0
            if (matrix[i][j] == 0 && !visited[i][j]) {
                matrix[i][j] = 2; // 填充为 2
            }
        }
    }
}

int main() {
    int n;
    cin >> n; // 输入矩阵大小
    vector<vector<int>> matrix(n, vector<int>(n)); // 定义 n x n 的矩阵
    vector<vector<bool>> visited(n, vector<bool>(n, false)); // 标记矩阵,用于记录外部 0 是否已访问

    // 输入矩阵
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> matrix[i][j]; // 逐个读取矩阵元素
        }
    }

    // 第一步:标记所有与边界连通的 0
    markOutsideZeroes(matrix, visited);

    // 第二步:将闭合圈内的 0 填充为 2
    fillInnerZeroes(matrix, visited);

    // 输出结果矩阵
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cout << matrix[i][j] << " "; // 输出矩阵元素
        }
        cout << endl; // 每行结束后换行
    }

    return 0;
}

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

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

相关文章

在Ubuntu22.04上源码构建ROS noetic环境

Ubuntu22.04上源码构建ROS noetic 起因准备环境创建工作目录并下载源码安装编译依赖包安装ros_comm和rosconsole包的两个补丁并修改pluginlib包的CMakeLists的编译器版本编译安装ROS noetic和ros_test验证 起因 最近在研究VINS-Mono从ROS移植到ROS2&#xff0c;发现在编写feat…

从dos上传shell脚本文件到Linux、麒麟执行报错“/bin/bash^M:解释器错误:没有那个文件或目录”

[rootkylin tmp]#./online_update_wars-1.3.0.sh ba51:./online_update_wars-1.3.0.sh:/bin/bash^M:解释器错误:没有那个文件或目录 使用scp命令上传文件到麒麟系统&#xff0c;执行shell脚本时报错 “/bin/bash^M:解释器错误:没有那个文件或目录” 解决方法&#xff1a; 执行…

react+hook+vite项目使用eletron打包成桌面应用+可以热更新

使用Hooks-Admin的架构 Hooks-Admin: &#x1f680;&#x1f680;&#x1f680; Hooks Admin&#xff0c;基于 React18、React-Router V6、React-Hooks、Redux、TypeScript、Vite2、Ant-Design 开源的一套后台管理框架。https://gitee.com/HalseySpicy/Hooks-Adminexe桌面应用…

华东师范大学数学分析第五版PDF习题答案上册及下册

“数学分析”是数学专业最重要的一门基础课程&#xff0c;也是报考数学类专业硕士研究生的专业考试科目。为了帮助、指导广大读者学好这门课程&#xff0c;编者编写了与华东师范大学数学科学学院主编的《数学分析》(第五版)配套的辅导用书&#xff0c;以帮助读者加深对基本概念…

FineBI漏斗图分析转化率计算,需要获取当前节点和上一节点的转化率,需要获取错行值实现方案

FineBI漏斗图分析转化率计算&#xff0c;当前节点和上一节点的转化率&#xff0c;需要获取错行值 下面这张图大家很熟悉吧&#xff0c;非常经典的漏斗转化率分析。 从漏斗图看到需要计算转化率&#xff0c;都需要获取上一步漏斗的值&#xff0c;比如计算上一个省份的门店数量…

Solana 区块链的技术解析及未来展望 #dapp开发#公链搭建

随着区块链技术的不断发展和应用场景的扩展&#xff0c;性能和可拓展性成为各大公链竞争的关键因素。Solana&#xff08;SOL&#xff09;因其高吞吐量、低延迟和低成本的技术特性&#xff0c;在众多区块链项目中脱颖而出&#xff0c;被誉为“以太坊杀手”之一。本文将从技术层面…

FPGA开发-逻辑分析仪的应用-数字频率计的设计

目录 逻辑分析仪的应用 数字频率计的设计 -基于原理图方法 主控电路设计 分频器设计 顶层电路设计 数字系统开发不但需要进行仿真分析&#xff0c;更重要的是需要进行实际测试。 逻辑分析仪的应用 测试方式&#xff1a;&#xff08;1&#xff09;传统的测试方式&#…

基于python Django的boss直聘数据采集与分析预测系统,爬虫可以在线采集,实时动态显示爬取数据,预测基于技能匹配的预测模型

本系统是基于Python Django框架构建的“Boss直聘”数据采集与分析预测系统&#xff0c;旨在通过技能匹配的方式对招聘信息进行分析与预测&#xff0c;帮助求职者根据自身技能找到最合适的职位&#xff0c;同时为招聘方提供更精准的候选人推荐。系统的核心预测模型基于职位需求技…

kubesphere环境-本地Harbor仓库+k8s集群(单master 多master)+Prometheus监控平台部署

前言&#xff1a;半月前在公司生产环境上离线部署了k8s集群Victoria Metrics(二开版)自研版夜莺 监控平台的搭建&#xff0c;下面我租用3台华为云服务器演示部署kubesphere环境-本地Harbor仓库k8s集群&#xff08;单master节点 & 单master节点&#xff09;Prometheus监控部…

车载诊断框架 --- UDS小白入门篇

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所有人的看法和评价都是暂时的&#xff0c;只有自己的经历是伴随一生的&#xff0c;几乎所有的担忧和畏惧…

强大的正则表达式——Easy

进入题目界面输入难度1后&#xff0c;让我们输入正则表达式&#xff08;regex&#xff09;&#xff1a; 目前不清楚题目要求&#xff0c;先去下载附件查看情况&#xff1a; import re import random# pip install libscrc import libscrcallowed_chars "0123456789()|*&q…

字节青训-小C的外卖超时判断、小C的排列询问

目录 一、小C的外卖超时判断 问题描述 测试样例 解题思路&#xff1a; 问题理解 数据结构选择 算法步骤 最终代码&#xff1a; 运行结果&#xff1a; 二、小C的排列询问 问题描述 测试样例 最终代码&#xff1a; 运行结果&#xff1a; ​编辑 一、小C的外卖超时判断…

游戏引擎学习第13天

视频参考:https://www.bilibili.com/video/BV1QQUaYMEEz/ 改代码的地方尽量一张图说清楚吧,懒得浪费时间 game.h #pragma once #include <cmath> #include <cstdint> #include <malloc.h>#define internal static // 用于定义内翻译单元内部函数 #…

C++11(五)----lambda表达式

文章目录 lambda表达式 lambda表达式 lambda表达式可以看作一个匿名函数 语法 [capture-list] (parameters) mutable -> return-type { statement } auto func1 [](int a, int b) mutable -> int {return a b; }; *capture-list&#xff1a;捕捉列表。编译器根据[]来 判…

CSS基础知识05(弹性盒子、布局详解,动画,3D转换,calc)

目录 0、弹性盒子、布局 0.1.弹性盒子的基本概念 0.2.弹性盒子的主轴和交叉轴 0.3.弹性盒子的属性 flex-direction row row-reverse column column-reverse flex-wrap nowrap wrap wrap-reverse flex-dirction和flex-wrap的组合简写模式 justify-content flex-s…

【Qt聊天室】客户端实现总结

目录 1. 项目概述 2. 功能实现 2.1 主窗口设计 2.2 功能性窗口 2.3 主界面功能实现 2.4 聊天界面功能实现 2.5 个人信息功能开发 2.6 用户信息界面设置功能 2.7 单聊与群聊 2.8 登录窗口 2.9 消息功能 3. 核心设计逻辑 3.1 核心类 3.2 前后端交互与DataCenter 4…

RK3568平台开发系列讲解(高级字符设备篇)IO 模型引入实验

🚀返回专栏总目录 文章目录 一、IO 的概念二、IO 执行过程三、IO 模型的分类阻塞 IO非阻塞 IOIO 多路复用信号驱动异步 IO沉淀、分享、成长,让自己和他人都能有所收获!😄 一、IO 的概念 IO 是英文 Input 和 Output 的首字母, 代表了输入和输出, 当然这样的描述有一点点…

简单实现QT对象的[json]序列化与反序列化

简单实现QT对象的[json]序列化与反序列化 简介应用场景qt元对象系统思路实现使用方式题外话 简介 众所周知json作为一种轻量级的数据交换格式&#xff0c;在开发中被广泛应用。因此如何方便的将对象数据转为json格式和从json格式中加载数据到对象中就变得尤为重要。 在python类…

【qt】控件2

1.frameGeometry和Geometry区别 frameGeometry是开始从红圈开始算&#xff0c;Geometry从黑圈算 程序证明&#xff1a;使用一个按键&#xff0c;当按键按下,qdebug打印各自左上角的坐标&#xff08;相当于屏幕左上角&#xff09;&#xff0c;以及窗口大小 Widget::Widget(QWid…

LeetCode654.最大二叉树

LeetCode刷题记录 文章目录 &#x1f4dc;题目描述&#x1f4a1;解题思路⌨C代码 &#x1f4dc;题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子…