华为od(D卷)路口最短时间问题

题目描述

假定街道是棋盘型的,每格距离相等,车辆通过每格街道需要时间均为 timePerRoad;

街道的街口(交叉点)有交通灯,灯的周期 T(=lights[row][col])各不相同;

车辆可直行、左转和右转,其中直行和左转需要等相应 T 时间的交通灯才可通行,右转无需等待。

现给出 n * m 个街口的交通灯周期,以及起止街口的坐标,计算车辆经过两个街口的最短时间。

其中:

  1. 起点和终点的交通灯不计入时间,且可以在任意方向经过街口
  2. 不可超出 n * m 个街口,不可跳跃,但边线也是道路(即:lights[0][0] -> lights[0][1] 是有效路径)

入口函数定义:

/**
 * @param lights:n*m个街口每个交通灯的周期,值范围[0, 120],n和m的范围为[1,9]
 * @param timePreRoad:相邻两个街口之间街道的通行时间,范围为[0,600]
 * @param rowStart:起点的行号
 * @param colStart:起点的列号
 * @param rowEnd:终点的行号
 * @param colEnd:终点的列号
 * @return lights[rowStart][colStart] 与 lights[rowEnd][colEnd] 两个街口之间的最短通行时间
 */
int calcTime(int[][] lights, int timePreRoad, int rowStart, int colStart, int rowEnd, int colEnd)

输入描述

第一行输入 n 和 m,以空格分隔

之后 n 行输入 lights矩阵,矩阵每行m个整数,以空格分隔

之后一行输入 timePerRoad

之后一行输入 rowStart colStart,以空格分隔

最后一行输入 rowEnd colEnd,以空格分隔

输出描述

lights[rowStart][colStart] 与 lights[rowEnd][colEnd] 两个街口之间的最短通行时间

示例1

输入
3 3
1 2 3
4 5 6
7 8 9
60
0 0
2 2

输出
245

说明
行走路线为 (0,0) -> (0,1) -> (1,1) -> (1,2) -> (2,2) 走了4格路,2个右转,1个左转,共耗时 60+0+60+5+60+0+60=245

思路

  1. 暴力解法回溯出所有路线,计算距离

  2. 在有权图(权值非负数)中求从起点到其他节点的最短路径算法: dijkstra 算法(dijkstra 算法可以同时求 起点到所有节点的最短路径)

dijkstra:

  • 第一步,选源点到哪个节点近且该节点未被访问过
  • 第二步,该最近节点被标记访问过
  • 第三步,更新非访问节点到源点的距离(即更新minDist数组)

注意:到达当前节点的最短距离,不一定能推导出下一个节点的最小距离

例如: 到达(1,2)的距离(0,0) -> (0,1) -> (0,2) ->(1,2) : 60*3+2+0 = 182;比(0,0) -> (0,1) -> (1,1) -> (1,2) 60*3+5+0 = 185; 182的线路小,但是这个线路不能推导出(2,2)的最优解, 所以minDist在存储时不能只存储距离,还要存储方向信息。

方向编号处理: 顺时针规定方向编号,从0开始
路口编号处理: 按照先行后列设置编号,从0开始(目的为了降低数组维度,降低for循环嵌套)

代码


public class Demo20 {
   
   
    // 方向顺序
    private static final int[][] dir = new int[][] {
   
   
            {
   
   -1, 0},
            {
   
   0, 1},
            {
   
   1, 0},
            {
   
   0, -1},

    };


    public static void main(String[] args) {
   
   
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {
   
   
            int rows = in.nextInt();
            int cols = in.nextInt();
            int[][] lights = new int[rows][cols];
            for (int i = 0; i < rows
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值