【洛谷P9303题解】AC代码- [CCC 2023 J5] CCC Word Hunt

在CCC单词搜索游戏中,单词可以隐藏在字母网格中,以直线或直角的方式排列。以下是对代码的详细注释和解题思路的总结:

传送门: https://www.luogu.com.cn/problem/P9303

代码注释

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>

using namespace std;

// 定义八个可能的搜索方向
const int dx[8] = {-1,-1, 0, 1, 1, 1, 0,-1}; // 北、东北、东、东南、南、西南、西、西北
const int dy[8] = { 0, 1, 1, 1, 0,-1,-1,-1};

int R, C; // 网格行数和列数
vector<string> grid; // 字母网格
string word; // 搜索区域分词
int word_len; // 单词长度

// 检查坐标是否在网格范围内
bool inBounds(int x, int y) {
    return x >= 0 && x < R && y >= 0 && y < C;
}

// 检查单词是否可以沿指定方向的直线排列
bool checkStraight(int x, int y, int dir) {
    for (int i = 0; i < word_len; ++i) {
        int nx = x + dx[dir] * i; // 计算下一个位置的行坐标
        int ny = y + dy[dir] * i; // 计算下一个位置的列坐标
        if (!inBounds(nx, ny) || grid[nx][ny] != word[i]) // 如果超出边界或字母不匹配
            return false; // 返回不匹配
    }
    return true; // 单词完全匹配
}

// 检查单词是否可以以L形排列(直角)
bool checkLShape(int x, int y, int dir1, int dir2, int split) {
    // 检查第一段(从起点到分割点)
    for (int i = 0; i < split; ++i) {
        int nx = x + dx[dir1] * i;
        int ny = y + dy[dir1] * i;
        if (!inBounds(nx, ny) || grid[nx][ny] != word[i])
            return false;
    }

    // 从分割点开始,沿新的方向检查剩余部分
    int lx = x + dx[dir1] * (split - 1);
    int ly = y + dy[dir1] * (split - 1);

    for (int i = split; i < word_len; ++i) {
        lx += dx[dir2]; // 更新行坐标
        ly += dy[dir2]; // 更新列坐标
        if (!inBounds(lx, ly) || grid[lx][ly] != word[i])
            return false;
    }
    return true; // 单词完全匹配
}

// 判断两个方向是否垂直
bool arePerpendicular(int dir1, int dir2) {
    return (dx[dir1] * dx[dir2] + dy[dir1] * dy[dir2]) == 0; // 点积为0则垂直
}

int main() {
    cin >> word;
    word_len = word.length();
    cin >> R >> C;
    grid.resize(R);

    // 读取网格
    for (int i = 0; i < R; ++i) {
        grid[i] = "";
        for (int j = 0; j < C; ++j) {
            string ch;
            cin >> ch;
            grid[i] += ch;
        }
    }

    int count = 0;

    // 遍历每个单元格作为起点
    for (int x = 0; x < R; ++x) {
        for (int y = 0; y < C; ++y) {
            if (grid[x][y] != word[0]) continue; // 跳过不匹配首字母的单元格

            // 检查所有可能的直线排列
            for (int d = 0; d < 8; ++d) {
                if (checkStraight(x, y, d))
                    count++;
            }

            // 检查所有可能的L形排列
            for (int d1 = 0; d1 < 8; ++d1) {
                for (int d2 = 0; d2 < 8; ++d2) {
                    if (d1 == d2 || !arePerpendicular(d1, d2))
                        continue; // 跳过相同方向或非垂直方向
                    for (int split = 2; split < word_len; ++split) { // 分割点至少在第二个字母
                        if (checkLShape(x, y, d1, d2, split))
                            count++;
                    }
                }
            }
        }
    }

    cout << count << endl; // 输出匹配次数
    return 0;
}

解题思路总结

  1. 输入读取:读取单词、网格的行数和列数,以及网格本身。
  2. 方向定义:定义八个可能的搜索方向,涵盖所有直线方向。
  3. 边界检查:确保坐标在网格范围内。
  4. 直线匹配:对于每个起点,检查是否可以沿八个方向之一形成直线排列。
  5. 直角匹配:对于每个起点,检查是否可以形成L形排列,确保两个方向垂直。
  6. 计数:统计所有可能的匹配方式,并输出总次数。

代码优点

  • 明确的方向定义:八个方向涵盖了所有可能的直线搜索方向。
  • 高效的边界检查:确保搜索过程中不越界。
  • 独立的匹配检查:直线和L形匹配的逻辑分离,代码结构清晰。
  • 垂直方向判断:通过点积判断两个方向是否垂直,数学上简洁有效。

代码缺点

  • 性能问题:对于较长的单词或较大的网格,递归搜索可能导致性能下降。
  • 重复计算:某些情况下可能会重复检查相同的路径。
  • 代码复杂度:涉及多个嵌套循环,可能影响可读性。

总结

该代码实现了对字母网格中单词的搜索,能够处理单词以直线或直角方式排列的情况。通过详细的注释和清晰的解题思路,代码易于理解和维护。

相关推荐
先吃饱再说2 小时前
判断回文字符串,从一行代码到双指针优化
算法
见过夏天2 小时前
C++ 基础入门完全指南
c++
黄敬峰4 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术6 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六9 小时前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术10 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize10 小时前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考1 天前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
CSharp精选营1 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
美团技术团队1 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法