【洛谷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形匹配的逻辑分离,代码结构清晰。
  • 垂直方向判断:通过点积判断两个方向是否垂直,数学上简洁有效。

代码缺点

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

总结

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

相关推荐
tangguofeng13 分钟前
基于分治策略的循环赛日程表问题的思路讲解
算法
Sayai14 分钟前
Neo4j 内嵌模式(Embedded)实战:Java 嵌入式 vs 服务端部署的写入性能对比与 GC 调优
java·开发语言·性能优化·neo4j·图数据库
hnjzsyjyj24 分钟前
洛谷 P1339:[USACO09OCT] Heat Wave G ← Bellman-Ford 算法
数据结构·bellman-ford 算法
起个名字费劲死了36 分钟前
VisionMaster集成深度学习算法(基础狗)
人工智能·深度学习·算法
lengxuenong39 分钟前
枚举例题分析
c++·算法·青少年编程
“AI国潮设计-小江”1 小时前
【SDXL实战】用AI生成“财神爷蛋糕×英歌舞人物”潮汕国潮甜品IP,附Prompt与批量生成思路
开发语言·人工智能·python·aigc
繁华的地方不一定留下你的脚印1 小时前
C++线程如何安全停止与唤醒:std::jthread、stop_token与condition_variable
开发语言·c++
Navigator_Z1 小时前
LeetCode //C - 1269. Number of Ways to Stay in the Same Place After Some Steps
c语言·算法·leetcode
2601_965742221 小时前
短视频脚本创作方法分享:本地生活类账号的起步思路
大数据·人工智能·算法·ai·新媒体运营·生活
caoerzhong1 小时前
跨境海外仓怎么管:JeeWMS 开源 Java 仓库管理系统打通头程、海外仓与尾程
java·开发语言·开源