最小路径和(DFS)

3502. 不同路径数

问题重述:

给定一个 n×m的二维矩阵,其中的每个元素都是一个 [1,9][1,9] 之间的正整数。

从矩阵中的任意位置出发,每次可以沿上下左右四个方向前进一步,走过的位置可以重复走。

走了 k次后,经过的元素会构成一个 (k+1) 位数。

请求出一共可以走出多少个不同的 (k+1) 位数。

输入格式

第一行包含三个整数 n,m,k。

接下来 n 行,每行包含 m 个空格隔开的整数,表示给定矩阵。

输出格式

输出一个整数,表示可以走出的不同 (k+1) 位数的个数。

数据范围

对于 30% 的数据, 1≤n,m≤2,0≤k≤2对于 100%100% 的数据,1≤n,m≤5,0≤k≤5,m×n>1输入样例:

3 3 2
1 1 1
1 1 1
2 1 1
输出样例:
5
样例解释

一共有 5 种可能的 3 位数:

111
112
121
211
212

问题分析:

本题要求计算不重复的最短路径,我们可以使用哈希表对路径进行记录,因为哈希表有不重复的特点,最后我们只需要输出哈希表的长度即为最短路径数。因为本题的数据范围比较小,我们可以使用深度优先算法对每一个点进行遍历,得到路径结果。

解法:

DFS深度优先

解题:

代码:
package cn.basic.算法;
import java.util.HashSet;
import java.util.Scanner;
/**
 * 给定一个 n×m 的二维矩阵,其中的每个元素都是一个 [1,9] 之间的正整数。
 * 从矩阵中的任意位置出发,每次可以沿上下左右四个方向前进一步,走过的位置可以重复走。
 * 走了 k 次后,经过的元素会构成一个 (k+1) 位数。
 * 请求出一共可以走出多少个不同的 (k+1) 位数。
 * 输入格式
 * 第一行包含三个整数 n,m,k。
 * 接下来 n 行,每行包含 m 个空格隔开的整数,表示给定矩阵。
 * 输出格式
 * 输出一个整数,表示可以走出的不同 (k+1) 位数的个数。
 * 数据范围
 * 对于 30% 的数据, 1≤n,m≤2,0≤k≤2
 * 对于 100% 的数据,1≤n,m≤5,0≤k≤5,m×n>1
 * 输入样例:
 * 3 3 2
 * 1 1 1
 * 1 1 1
 * 2 1 1
 * 输出样例:
 * 5
 * 样例解释
 * 一共有 5 种可能的 3 位数:
 * 111
 * 112
 * 121
 * 211
 * 212
 */
public class Main5 {
    static int n,m,k;
    //定义一个set集合对路径进行保存,可以保证不出现重复
    static HashSet<String> path = new HashSet<>();
    //定义路径方向
    static int [][]d = {{1,0},{-1,0},{0,1},{0,-1}};
    //二维矩阵初始化
    static int [][]arrays;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        //输入三个整数
        n = scanner.nextInt();
        m = scanner.nextInt();
        k = scanner.nextInt();
        String str = "";
        arrays = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                arrays[i][j] = scanner.nextInt();
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                //对每一个顶点使用深度优先算法
                dfs(str,i,j);
            }
        }
        System.out.println(path.size());
    }
    //深度优先
    static void dfs(String str,int x,int y){
        //若步数已经达到,或者超出范围则退出方法
        if (str.length() == k+1){
            path.add(str);
            return;
        }
        //进行路径的计算
        str +=arrays[x][y];
        for (int i = 0; i < 4; i++) {
            //开始,上下左右方向行进
            x += d[i][0];
            y += d[i][1];
            if (x >= 0 && x < n && y >= 0 && y < m){
                dfs(str,x,y);
            }
            //回退
            x-=d[i][0];
            y-=d[i][1];
        }
    }
}

代码分析:

首先定义一个HashSet,用于存储最短路径(存储字符串),同时对路径进行去重(因为HashSet内元素不能重复),定义一个二维数组用于存放上下左右方向x、y方向所需的变化量。定义三个整数,一个为行数,一个为每行的整数个数,一个为从某个顶点开始走的步数。定义一个二维数组,用于存储元素。定义一个dfs方法,参数为字符串(用于保存最短路径的字符串),以及当前所在顶点的位置(x、y)。方法内部,首先进行条件判断,如果最短路径所经过的步数已经达到了k,那么最短路径的长度应该为k+1,此时将该路径添加进哈希表中,同时退出方法。路径未达到最短,那么将当前所在顶点的数据添加进路径字符串尾部,因为每个顶点可以上下左右四个方向前进,每个顶点进行4次循环,更新x、y坐标,如果满足条件,那么调用dfs方法。进入方法后,继续进行条件的判断,不满足则更新路径以及x、y坐标再次调用dfs方法传入对应str、x、y,如果满足了条件,则退出当前方法,回到上一次执行该方法的时候,退出后代码应在当前位置

 if (x >= 0 && x < n && y >= 0 && y < m){
                dfs(str,x,y);
          //退出时代码应到达这里
          }

退出方法后,继续向下执行,因为此时的x、y是达到最短路径要求的最后一个顶点的位置,我们需要返回上一个顶点,所以对x、y进行回退更新操作(也就是减掉原来加上的值),继续未完成的循环,更改前进方向继续调用dfs方法。从二维数组的第一个顶点开始直到最后一个顶点结束,HashSet的长度即为最短路径的个数,输出长度即可。

深度优先遍历算法总结:

基本思想:按照某一指定方向,一直前进,直到没有路可走,则返回上一步,更改方向继续前进,没有路可走后在返回当前的上一步知道遍历完所有顶点。

dfs算法基本模板:
void dfs(){
    //判断是否满足条件,满足条件则退出方法
    if(){
        对满足条件的记录进行保存
        return;
    }
    //所需要走的方向,进行循环
    for(){
        //更新步数重新调用dfs方法进行递归,最好调用前进行条件判断,满足条件才调用
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值