[编程题]: 给定步长走矩阵(2021华为机试)

本文探讨了在固定步长下,使用深度优先搜索(DFS)算法判断能否从矩阵左上角到达右下角的问题。通过实例展示了算法的实现过程,并对比了动态规划方法的局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

走矩阵宫格

给出一个矩阵,0表示没有地砖,不能落地;1表示有地砖,可以落地。给定一个固定步长S(S > 0),保证左上和右下为1,问能否从左上到达右下,能则输出1,不能输出0.(每次走的步长都是固定的,走的时候只能上、下、左、右四个方向,不能拐弯也不能走斜线
输入描述:
第一行一个整数S,为步长;
第二行两个整数M,N,代表矩阵为 M * N;
接下来M行,每行N个整数,代表矩阵
示例1

输入
2
3 5
1 0 1 0 0
0 1 1 0 1
0 0 1 0 1
输出
1

示例2(我自己试验构造的)

输入
2
9 9
1 0 1 0 1 0 0 1 0
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 1 0 1 0 1 0 1
输出
1

解题思路
刚开始一看就想到了动态规划,以前刷题,剑指offer也有类似的题。
但是动态规划应该不能用在这里,应为每次走都能上、下、左、右四个方向走,有可能往回走。而动态规划只适用于只能向下或向右两个方向走,不会往回走。
例如示例2中,在矩阵的 (2, 1) 处就需要往回走一步才能最终到达,动态规划从上到下,从左到右计算dp矩阵,不能往回走。(所以刷题不能死刷题,要灵活应用,因势利导,不能墨守成规)
因此,这题适合采用DFS的方法。代码如下:
Java

import java.util.Scanner;

public class Main{
    private static int m;
    private static int n;
    private static boolean[][] visited; //标记已经访问的点,否则递归爆栈
    private static boolean[][] dp; //标记那些点可以到达

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int s = input.nextInt();
        m = input.nextInt();
        n = input.nextInt();
        int[][] board = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                board[i][j] = input.nextInt();
            }
        }
        if (s < 1 || m < 1 || n < 1) System.out.println(0);
        visited = new boolean[m][n];
        dp = new boolean[m][n];
        dp[0][0] = true;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                dfs(board, i, j, s);
                System.out.print(dp[i][j] + " ");
            }
            System.out.println();
        }
        if (visited[m - 1][n - 1]) System.out.println(1);
        else System.out.println(0);
    }

    public static void dfs(int[][] board, int i, int j, int s) {
        if (i >= 0 && i < m && j >= 0 && j < n && !visited[i][j]) {
            visited[i][j] = true; //标记当前节点被访问
            //上
            for (int k = 1; k <= s; k++) {
                if (i - k >= 0 && board[i - k][j] == 1 && !visited[i - k][j]) {
                    dp[i - k][j] = true; //上面的点可以到达
                    dfs(board, i - k, j, s);
                }
            }
            //下
            for (int k = 1; k <= s; k++) {
                if (i + k < m &&board[i + k][j] == 1 && !visited[i + k][j]) {
                    dp[i + k][j] = true; //下面的点可以到达
                    dfs(board, i + k, j, s);
                }
            }
            //左
            for (int k = 1; k <= s; k++) {
                if (j - k >= 0 && board[i][j - k] == 1 && !visited[i][j - k]) {
                    dp[i][j - k] = true; //左边的点可以到达
                    dfs(board, i, j - k, s);
                }
            }
            //右
            for (int k = 1; k <= s; k++) {
                if (j + k < n && board[i][j + k] == 1 && !visited[i][j + k]) {
                    dp[i][j + k] = true; //右边的点可以到达
                    dfs(board, i, j + k, s);
                }
            }
        }
    }
}
示例1
true false true false false true 
false true true false false false 
false true false true false true 
1
示例2
true false true false true false false false false 
false false false false false false false false false 
false false false false true false false false false 
false false false false false false false false false 
false false true false true false false false false 
false false false false false false false false false 
false false true false false false false false false 
false false false false false false false false false 
false false true false true false true false true 
1

C++

#include <iostream>
#include<vector>

using namespace std;

int m, n;
vector<vector<int>> board;

void dfs(vector<vector<bool>>& visited, vector<vector<bool>>& dp, int i, int j, int s) {
    if (i >= 0 && i < m && j >= 0 && j < n && !visited[i][j]) {
        visited[i][j] = true;
        //向上DFS
        if (i - s >= 0 && board[i - s][j] == 1 && !visited[i - s][j]) {
            dp[i - s][j] = true;
            dfs(visited, dp, i - s, j, s);
        }

        //向下DFS
        if (i + s < m && board[i + s][j] == 1 && !visited[i + s][j]) {
            dp[i + s][j] = true;
            dfs(visited, dp, i + s, j, s);
        }

        //向左DFS
        if (j - s >= 0 && board[i][j - s] == 1 && !visited[i][j - s]) {
            dp[i][j - s] = true;
            dfs(visited, dp, i, j - s, s);
        }

        //向右DFS
        if (j + s < n && board[i][j + s] == 1 && !visited[i][j + s]) {
            dp[i][j + s] = true;
            dfs(visited, dp, i, j + s, s);
        }
    }
}

int main() {
    int s;
    cin >> s >> m >> n;
    int num;
    vector<int> line;
    for (int i = 0; i < m; i++) {
        line.clear();
        for (int j = 0; j < n; j++) {
            cin >> num;
            line.push_back(num);
        }
        board.push_back(line);
    }
    vector<vector<bool>> dp(m, vector<bool>(n, false));
    vector<vector<bool>> visited(m, vector<bool>(n, false));
    dp[0][0] = true;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            dfs(visited, dp, i, j, s);
            if (dp[i][j]) cout << "true ";
            else cout << "false ";
        }
        cout << endl;
    }
    if (dp[m - 1][n - 1]) cout << 1 << endl;
    else cout << 0 << endl;
    return 0;
}
示例1
true false true false false true
false true true false false false
false true false true false true
1

示例2
true false true false true false false true false
false false false false false false false false false
false false false false true false false false false
false false false false false false false false false
false false true false true false false false false
false false false false false false false false false
false false true false false false false false false
false false false false false false false false false
false false true false true false true false true

可见dp矩阵记录的结果,若用动态规划将出现遗漏

108题中有部分题目重合,因此么有收录在压缩文件中。 华为 ├─001 字符串最后一个单词长度 │ └─Source ├─002 计算字符个数 │ └─Source ├─003 明明的随数 │ └─Source ├─004 字符串分隔 │ └─Source ├─005 进制转换 │ └─Source ├─006 质数因子 │ └─Source ├─007 取近似值 │ └─Source ├─008 合并表记录 │ └─Source ├─009 提取不重复的整数 │ └─Source ├─010 字符个数统计 │ └─Source ├─011 数字颠倒 │ └─Source ├─012 字符串反转 │ └─Source ├─013 句子逆序 │ └─Source ├─014 字典序排序 │ └─Source ├─015 求int型正整数在内存中存储是1的个数 │ └─Source ├─016 购物单 │ ├─Debug │ ├─Source │ │ └─Debug │ ├─Source - 时间优先 │ │ └─Debug │ └─Source - 空间优先 │ ├─Debug │ └─Release ├─017 坐标移动 ├─018 识别IP地址分类统计 │ └─Source │ └─Debug ├─019 错误记录 ├─020 密码验证合格程序 ├─021 密码破解 ├─023 删除字符串中出现次数最少字符 │ └─Source │ └─Debug ├─024 合唱队 │ └─Source │ ├─Debug │ └─Release ├─025 数据分类处理 │ └─Source │ └─Debug ├─026 查找兄弟单词 │ └─Source │ └─Debug ├─027 素数伴侣 │ └─Source │ └─Debug ├─028 字符串合并处理 │ └─Source │ └─Debug ├─030 密码截取(查找最长回文字符串) ├─031 蛇形矩阵 │ └─Source │ └─Debug ├─033 判断IP是否属于同一子网 │ └─Source │ └─Debug ├─034 称砝码 │ └─Source │ └─Debug ├─035 学英语 │ └─Source │ └─Debug ├─036 迷宫问题 │ └─Source │ └─Debug ├─037 数独问题 │ └─Debug ├─038 名字漂亮度 │ └─Source │ └─Debug ├─039 字符串截取 │ └─Source │ └─Debug ├─040 单链表删除数据 │ └─Source │ └─Debug ├─041 多线程 │ └─Source │ ├─Backup │ ├─Debug │ │ └─041.tlog │ └─Release │ └─041.tlog ├─042 表达式计算 │ └─Source │ └─Debug ├─043 计算字符串距离 │ └─Source │ └─Debug ├─044 杨辉三角形变形 ├─046 挑7 ├─047 完全数 │ └─Debug ├─048 高精度加法 ├─049 输出n个数中最小的k个 │ └─Debug ├─050 找出字符串只出现一次的字符 │ └─Debug ├─051 组成一个偶数最接近的2个质数 │ └─Debug ├─052 M个苹果放入N个盘子 ├─053 查找整数二进制中1的个数 ├─054 DNA子串 ├─055 MP3光标位置 │ └─Source │ └─Debug ├─056 查找2个字符串最大相同子串 │ └─Debug ├─057 配置文件恢复 │ └─Source │ └─Debug ├─058 24点计算 │ └─Debug ├─059 成绩排序 ├─060 矩阵相乘 ├─061 矩阵乘法次数计算 ├─062 字符串通配符 │ └─Debug ├─066 命令行解析 │ └─Source │ └─Debug ├─067 最大相同子串长度 │ └─Debug ├─068 火车编号进站 │ └─Debug ├─072 数组合并 ├─074 埃及分数 │ └─Source │ └─Debug ├─076 密码截取 │ └─Source ├─077 求最大连续bit数 ├─078 密码强度 ├─079 扑克牌大小 │ └─Source │ └─Debug ├─081 合法IP ├─082 棋盘格子法 ├─083 在字符串中找出连续最长数字串 ├─084 int数组分组,两组和相等 │ └─Source │ └─Debug ├─086 人民币转换 │ └─Source │ └─Debug ├─087 表示数字 ├─090 自动售货系统 │ └─Source │ └─Debug └─091 24点输出 └─Debug
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值