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

走矩阵宫格

给出一个矩阵,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矩阵记录的结果,若用动态规划将出现遗漏

猜你喜欢

转载自blog.csdn.net/qq_27198345/article/details/107968426
今日推荐