【2023百度之星备赛】AcWing 5165. CCC单词搜索(秋季每日一题2023)

news/2024/7/20 22:30:51 标签: 深度优先, 算法

题目

https://www.acwing.com/problem/content/5168/

题目大意:

给定一个单词和一个字符矩阵,要求找出单词在字符矩阵中出现了多少次。出现定义为:

  • 出现在一条直线段上,线段包括水平、垂直、正对角、反对角线段
  • 出现在两条垂直相交的直线段上,线段包括水平、垂直、正对角、反对角线段

枚举思路(没做出来)

我一开始的思路就是枚举思路,我画出来了字符串出现的所有可能的情况:

  1. 直线段一共有4种:水平方向、垂直方向、正对角线方向、反对角线方向
  2. 转弯线段一共有8种:水平+垂直(共4种)、正对角线+反对角线(共4种)

然后每种情况又包括两种判断:正序遍历判断和倒序遍历判断(两种情况都算出现了这个字符串)。情况统计完了之后,对于直线段还比较容易,按照4种情况遍历就行了。但是对于转弯的情况,发现要写的时候觉得有点麻烦。主要是不知道转弯的时候,变方向的代码要怎么写

DFS思路

这里参考了y总的思路,用dfs来写。首先遍历起点,对于每个点来说,有8个方向可以走。对于接下来的每一步来说,有两种情况,转弯和不转弯。具体来说:

  1. 不转弯:沿着当前方向遍历一步
  2. 转弯:先转弯90度,然后沿着新的方向遍历一步

直到走过的步数恰好等于单词w的长度,此时说明单词出现了一次,答案加1。

时间复杂度分析

  1. 遍历起点: R ∗ C = 100 ∗ 100 R * C = 100 * 100 RC=100100
  2. 遍历8个方向: 8 8 8
  3. 转弯和不转弯:单词最长有6个字母,不转弯的情况只有 1 1 1种,转弯的情况有 ( 6 − 1 ) ∗ 2 (6-1)* 2 612种(6个字母,5个转弯点,每个点有两个转弯方向)

所以程序语句执行总次数最多为 100 ∗ 100 ∗ 8 ∗ ( 5 ∗ 2 + 1 ) 100 * 100 * 8 * (5 * 2 + 1) 100100852+1,数量级为 1 0 6 10^6 106,小于 1 0 8 10^8 108,不会TLE。

代码细节

首先8个方向用两个增量数组来存:

int dx[] = {-1,-1,0,1,1,1,0,-1};
int dy[] = {0,1,1,1,0,-1,-1,-1};

对于转弯来说,如果当前方向编号为d,转弯后的方向编号为new_d,则:

new_d = d ^ 2 ^ (i << 2)

图示如下(图片来自y总视频讲解https://www.acwing.com/video/4876/):

在这里插入图片描述

说明:

随便拿一组转弯的点来说明:方向0、方向6、方向2,它们对应的二进制分别为:

  • 方向0:000
  • 方向6:110
  • 方向2:010

将方向0变成方向6或者方向2,可以发现从右往左数,第1位是不变的,第2位进行亦或,第3位变成方向6的时候亦或、变成方向2的时候不变。用二进制表示就是d ^ 2 ^ (i << 2),当i等于0的时候第3位不变,当i等于1的时候第3位亦或。(没做过这种题,表示真的很难想到。。。)

对于dfs函数来说,有5个参数:

  • x:x坐标
  • y:y坐标
  • d:方向编号
  • u:dfs到单词w的第几个字符了
  • turned:是否转过弯了
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 110;

string w;
int r, c;

char g[N][N];
int dx[] = {-1,-1,0,1,1,1,0,-1};
int dy[] = {0,1,1,1,0,-1,-1,-1};

int ans;

void dfs(int x, int y, int d, int u, bool turned) {
    /* 
        走出下一步的时候,分几种情况:
        
        1. 往哪个方向走
        2. 是否转弯走
    */
    
    // x, y表示坐标; d表示方向编号; u表示dfs到第几个字符了; turned表示是否转弯了
    if (x < 0 || x >= r || y < 0 || y >= c) return ; // 越界
    if (g[x][y] != w[u]) return ; // 字符不相同
    
    if (u == w.size() - 1) ans ++ ;
    else {
        // 不转弯
        dfs(x + dx[d], y + dy[d], d, u + 1, turned);
        
        // 转弯
        if (u > 0 && !turned) { 
        // 这里判断转弯的时候,要加一个判断u>0,即从第2个字符开始判断转弯,第一个字符是不能转弯的
            for (int i = 0; i < 2; i ++ ) {
                int new_d = d ^ 2 ^ (i << 2);
                dfs(x + dx[new_d], y + dy[new_d], new_d, u + 1, true);
            }
        }
    }
}

int main() {
    cin >> w;
    cin >> r >> c;
    
    getchar();
    for(int i = 0; i < r; i ++ ) {
        for(int j = 0; j < c; j ++ ) {
            scanf("%c ", &g[i][j]);
        }
    }
    
    for(int i = 0; i < r; i ++ ) {  // 遍历起点x坐标
        for(int j = 0; j < c; j ++ ) {  // 遍历起点y坐标
            for(int d = 0; d < 8; d ++ ) {  // 遍历8个方向
                dfs(i, j, d, 0, false);
            }
        }
    }
    
    cout << ans << endl;
    return 0;
}

总结

8个方向的方向数组:

int dx[] = {-1,-1,0,1,1,1,0,-1};
int dy[] = {0,1,1,1,0,-1,-1,-1};

对于方向编号d(方向编号从0编号到7)来说,旋转90°得到的新的方向编号new_d:

d ^ 2 ^ (0 << 2)  // 顺时针旋转90°
d ^ 2 ^ (1 << 2)  // 逆时针旋转90° 

参照这个结论,应该也能类似地推出旋转180°、沿y轴镜像、沿x轴镜像,由于这个题没用到,我就不写了。


http://www.niftyadmin.cn/n/4982227.html

相关文章

强化学习(2)

强化学习(1) 1.多智能体深度强化学习重要性采样 多智能体深度强化学习&#xff08;Multi-Agent Deep Reinforcement Learning&#xff0c;MADRL&#xff09;是指在多智能体环境下使用深度强化学习算法进行协同学习。重要性采样&#xff08;Importance Sampling&#xff09;是…

CSS按钮-跑马灯边框

思路很简单&#xff0c;实现方法有很多很多。但是大体思路与实现方法都类似&#xff1a;渐变色 动画&#xff0c;主要区别在动画的具体实现 0、HTML 结构 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><titl…

Ubuntu20.04如何更换国内源-阿里云源

1.备份源文件 cp /etc/apt/sources.list /etc/apt/sources.list.bak 2.打开源文件&#xff0c;注释默认的源 vim /etc/apt/sources.list ## 注释原本内容 # deb http://mirrors.ivolces.com/ubuntu/ focal main restricted universe multiverse # deb-src http://mirrors.ivolc…

Qt:界面实时响应鼠标拖动绘制

采用双缓冲实现界面实时响应鼠标的拖动绘制。 思想如下&#xff1a;首先需要两张画布pix和tempPix&#xff0c;他们都是QPixmap实例&#xff1b;pix用来保存初始界面或上一阶段以完成的绘制&#xff1b;tempPix用来作为鼠标拖动时的实时界面绘制&#xff1b;当鼠标左键按下后拖…

【单片机】有人WH-LTE-7S1 4G cat1 模块连接服务器,教程,记录

文章目录 4G cat1 模块封装引脚名称功能拓扑图串口模块调试WH-LTE-7S1 4G cat1 模块 我买的这个模块内置了电信卡&#xff0c;不用插电话卡就能用&#xff0c;要插也行&#xff0c;在背面。 ⚫ 5-16V 宽电压供电 ⚫ LTE Cat 1&#xff0c;搭载 4G 网络&#xff0c;低时延&…

【Android】AES解密抛出异常Cipher functions:OPENSSL_internal:WRONG_FINAL_BLOCK_LENGTH

Java使用AES加密的时候没得问题&#xff0c;但是在解密的时候就出错了&#xff0c;一起来找找原因吧。 首先&#xff0c;Java运行的代码如下&#xff0c;使用AES加解密 Cipher cipher Cipher.getInstance("AES/CBC/NOPadding"); //...主要问题 可调试运行控制台抛…

pytorch多进程处理数据的代码模板

pytorch多进程处理数据的代码模板 import argparse import functools import gc import logging import math import os import random import shutil from pathlib import Pathimport accelerate import datasets import numpy as np import torch import torch.nn.functiona…

ROS中使用Navigation报错信息

在ROS中使用遇到了几个Navigation报错信息&#xff0c;在这里进行下记录&#xff1a; [ WARN] [1688134727.429227824]: The origin for the sensor at (7.35, 13.12) is out of map bounds. So, the costmap cannot raytrace for it. 解决办法&#xff1a; [ WARN] [16881…