含红绿灯的街道车辆从起点到终点的最短时间(华为od机考题)

一、题目

1.原题

假定街道是棋盘型的,每格距离相等,车辆通过每格街道需要时间均为 timePerRoad;
街道的街口(交叉点)有交通灯,灯的周期T(=lights[row][col])各不相同;
车辆可直行、左转和右转,其中直行和左转需要等相应T时间的交通灯才可通行,右转无需等待。

现给出 n*m 个街口的交通灯周期,以及起止街口的坐标,计算车辆经过两个街口的最短时间。
其中:
1)起点和终点的交通灯不计入时间,且可以任意方向经过街口;
2)不可超出 n*m 个街口,不可跳跃,但边线也是道路(即 lights[0][0] -> lights[0][1] 是有效路径)。

2.题目要求

入口函数定义:
* lights : n*m 个街口每个交通灯的周期,值范围[0,120],n和m的范围为[1,9]
* timePerRoad : 相邻两个街口之间街道的通过时间,范围为[0,600]
* rowStart : 起点的行号
* colStart : 起点的列号
* rowEnd : 终点的行号
* colEnd : 终点的列号
* return : lights[rowStart][colStart] 与 lights[rowEnd][colEnd] 两个街口之间的最短通行时间

int calcTime(int[][] lights,int timePerRoad,int rowStart,int colStart,int rowEnd,int colEnd)

3.题目理解

含红绿灯的街道车辆从起点到终点的最短时间(华为od机考题)_第1张图片

含红绿灯的街道车辆从起点到终点的最短时间(华为od机考题)_第2张图片

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

直行是对当前方向状态的继承,左右转已经包含了所有的可移动方向(上下左右),但要注意边界。

直行和左转需要等相应T时间的交通灯:虽然说是周期,但只是叠加T,简化了问题,并未动态计算总时间。

当前方向是绝对的!!!转向是相对的!!

(当位置在上/下边界时,当前方向为左则不可再往右/左当前方向为右则不可以再往左/右;当位置为左/右边界时,当前方向为上则不可往左/右当前方向为下则不可以再往右/左。)

(2)计算车辆经过两个街口的最短时间:从起点到终点路上花的最短时间,不包括起点和终点的等灯时间。

联想过马路,我在(0,0)路口准备出发前往(0,1)需要等待(0,1)路口的红绿灯,加上我的行走用时,就是我这一小段距离的用时。

经过两个街口的最短时间,即路径上所有段路线所花时间(x个timePerRoad)+随方向状态而动的所有节点等待值

二、思路和代码过程

1.思路

定义一个动点类:横纵坐标:row col ,用时:spendtime ,面向:facedirection ,转向:movedirection。

①初始化起点,给它赋值四个面向(绝对位置),0上,1右,2下,3左(顺时针,与遍历顺序一致);

②动点当前值与移动方向叠加,对在边界内的动点进行计算;

③将计算完的动点存入根据用时从小到大排列的优先队列,投入递归继续计算;

④遍历到终点坐标返回当前时间(因为优先队列的特性,拿取的最顶端就是最小的)。

2.代码过程

①main函数

 public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        //输入时间周期数组
        System.out.println("请输入车辆通过每格街道需要的时间timePerRoad[0,600]:");
        int timePerRoad = sc.nextInt();
        if (timePerRoad>=0&&timePerRoad<=600){
            System.out.println("时间timePerRoad:"+timePerRoad+",设置成功!");
        }else {
            System.out.println("非法输入!");
            return;
        }
        //输入棋盘长宽
        System.out.println("请输入街道的长n和宽m[1,9]:");
        int n = sc.nextInt();
        int m = sc.nextInt();
        if (n>=1 && n<=9 && m>=1 && m<=9){
            System.out.println("街道长n:"+n+",宽m:"+m+",设置成功!");
        }else {
            System.out.println("非法输入!");
            return;
        }
        //输入交通灯周期数组
        System.out.println("请输入n*m 个街口的交通灯周期T(=lights[row][col])[0,120]:");
        int[][] lights = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                lights[i][j] = sc.nextInt();
                if (lights[i][j]>=0&&lights[i][j]<=120){
                    System.out.println("位置["+i+"]["+j+"]处的交通灯时间T:"+lights[i][j]+",设置成功!");
                }else {
                    System.out.println("非法输入!");
                    return;
                }
            }
        }
        System.out.println("交通灯周期设置成功:");
        for (int[] row : lights) {
            System.out.println(Arrays.toString(row));
        }
        //输入起止街口的坐标
        System.out.println("请输入起点的行号rowStart:");
        int rowStart = sc.nextInt();
        System.out.println("请输入起点的列号colStart:");
        int colStart = sc.nextInt();
        System.out.println("请输入终点的行号rowEnd:");
        int rowEnd = sc.nextInt();
        System.out.println("请输入终点的列号colEnd:");
        int colEnd = sc.nextInt();

        //int time = calcTime(lights,timePerRoad,rowStart,colStart,rowEnd,colEnd);
        System.out.println("车辆经过两个街口的最短时间为:"+calcTime(lights,timePerRoad,rowStart,colStart,rowEnd,colEnd));//从起点到终点的最短时间
    }

②方向数组

public static int[][] DIRECTION = {
            {0,1},//上up0
            {1,0},//右right1
            {0,-1},//下down2
            {-1,0}//左left3
    };

③calcTime方法

 private static int calcTime(int[][] lights, int timePerRoad, int rowStart, int colStart, int rowEnd, int colEnd) {

        //----------------------------------
        int n = lights.length;
        int m = lights[0].length;
        //
        PriorityQueue pqMoveSpot = new PriorityQueue<>(
                Comparator.comparingInt(MoveSpot::getTimeSpend));
        MoveSpot start = new MoveSpot(rowStart,colStart,0,-1, MoveSpot.Move.NoMoveDirection);
        pqMoveSpot.add(start);

        //当优先队列不为空时,当前只存了start点
        MoveSpot startMoveSpot = pqMoveSpot.poll();
        //赋值
        int startx = startMoveSpot.position[0];//row
        int starty = startMoveSpot.position[1];//col
        int startTime = startMoveSpot.timeSpend;//时间
        int startfaceDir = startMoveSpot.FaceDirection;//面向
        MoveSpot.Move startmoveDir = startMoveSpot.direction;//转向
        //起点初始化,无面向无转向,面向可为可上下左右
        if (startfaceDir==-1&&startmoveDir== MoveSpot.Move.NoMoveDirection){
            for (int i=0;i<4;i++){
                //上
                if (i==0){
                    startfaceDir = 0;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
                //右
                if (i==1){
                    startfaceDir = 1;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
                //下
                if (i==2){
                    startfaceDir = 2;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
                //左
                if (i==3){
                    startfaceDir = 3;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
            }
        }
        /*
            for (int i=0;i<4;i++){
                System.out.println("看看初始化好没"+pqMoveSpot.poll());
                }
         */

        shortesPassTime=findMoveRoad(pqMoveSpot,rowEnd,colEnd,lights,timePerRoad);//=======================调用
       /* if (!pqMoveSpot.isEmpty()){
        ///    shortesPassTime=pqMoveSpot.peek().getTimeSpend();
        }*/
        //时间=路线经过格子数量*tPR+经过格子的灯周期累计(右转=0/直左=T) 算路线?根据累积量来?
        //起点终点时间不计算
        return shortesPassTime;
    }

④findMoveRoad方法

private static int findMoveRoad(PriorityQueue pqMoveSpot,int rowEnd,int colEnd,int[][] lights,int timePerRoad) {
        int n = lights.length;
        int m = lights[0].length;
        PriorityQueue newpqMoveSpot = new PriorityQueue<>(
                Comparator.comparingInt(MoveSpot::getTimeSpend));
        while (!pqMoveSpot.isEmpty()) {
            //从队列中拿出放入当前动点
            MoveSpot currentMoveSpot = pqMoveSpot.poll();
            //赋值
            int x = currentMoveSpot.position[0];//row
            int y = currentMoveSpot.position[1];//col
            int currentTime = currentMoveSpot.timeSpend;//时间
            int currentfaceDir = currentMoveSpot.FaceDirection;//面向
            MoveSpot.Move currentmoveDir = currentMoveSpot.direction;//转向

            //当到了终点就返回时间
            if (x == rowEnd && y == colEnd) {
                return currentTime;
            }

            //遍历四个方向
            for (int i = 0; i < 4; i++) {
                x = currentMoveSpot.position[0];//row
                y = currentMoveSpot.position[1];//col
                currentTime = currentMoveSpot.timeSpend;//时间
                currentfaceDir = currentMoveSpot.FaceDirection;//面向
                currentmoveDir = currentMoveSpot.direction;//转向
                //eg:i=0,取DIRECTION[0][0]与DIRECTION[0][1]即向上(x+0,y+1)
                int newX = x + DIRECTION[i][0];
                int newY = y + DIRECTION[i][1];
                //在边界内
                if (newX >= 0 && newX < n && newY >= 0 && newY < m) {
                    MoveSpot.Move movedirection = currentmoveDir;
                    if (currentfaceDir == i) {//面向一致
                        currentTime = currentMoveSpot.timeSpend;
                        movedirection = MoveSpot.Move.GoStraight;
                        currentTime = currentTime + lights[newX][newY] + timePerRoad;//直行时间为交通灯等待时间+行走时间
                        currentfaceDir = i;
                    } else {//面向不一致
                        if (Math.abs(currentfaceDir - i) == 2) {//若需要转两次
                            continue;
                        } else {
                            //01 12 23 30右转
                            if (i - currentfaceDir == 1 || (currentfaceDir == 3 && i == 0)) {
                                currentTime = currentMoveSpot.timeSpend;
                                movedirection = MoveSpot.Move.TurnRight;
                                currentTime = currentTime + timePerRoad;//右转时间为行走时间
                                currentfaceDir = i;
                                }
                            //03 10 21 32左转
                            else if (currentfaceDir - i == 1 || (currentfaceDir == 0 && i == 3)) {
                                currentTime = currentMoveSpot.timeSpend;
                                movedirection = MoveSpot.Move.TurnLeft;
                                currentTime = currentTime + lights[newX][newY] + timePerRoad;//左转时间为交通灯等待时间+行走时间
                                currentfaceDir = i;
                            }
                        }
                    }
                    //加入队列
                    MoveSpot newSpot = new MoveSpot(newX, newY, currentTime, currentfaceDir, movedirection);
                    newSpot.position[0] = newX;
                    newSpot.position[1] = newY;
                    newSpot.timeSpend = currentTime;
                    newSpot.direction = movedirection;
                    newSpot.FaceDirection = currentfaceDir;
                    newpqMoveSpot.offer(newSpot);
                }//边界内判断
            }//四方向循环
        }
        /*
        for (int i = 0; i < 10; i++) {
            System.out.println("newpq检查:"+newpqMoveSpot.poll());
        }
         */
        shorttime = findMoveRoad(newpqMoveSpot, rowEnd, colEnd, lights, timePerRoad);
        return shorttime;
    }

⑤动点类

//定义一个动点类
    public static class MoveSpot {
        private int[] position = new int[2];//位置 {row,col}
        private int timeSpend;//用时
        private int FaceDirection;//面向
        private Move direction;//转向

        public class FaceDirection{
            public static final int NULL = -1;
            public static final int UP = 0;
            public static final int DOWN = 1;
            public static final int LEFT = 2;
            public static final int RIGHT = 3;
        }
        //转向枚举
        public enum Move {
            NoMoveDirection,GoStraight,TurnLeft,TurnRight;
        }

        //构造函数
        public MoveSpot(int row , int col , int timeSpend, int faceDirection,Move direction) {
            this.position[0] = row;//位置行列
            this.position[1] = col;
            this.timeSpend = timeSpend;
            this.FaceDirection = faceDirection;
            this.direction = direction;
        }

        //方法
        //位置
        public int[] getPosition() {
            return position;
        }
        public void setPosition(int row, int col) {
            this.position[0] = row;
            this.position[1] = col;
        }
        //时间
        public int getTimeSpend() {
            return timeSpend;
        }
        public void setTimeSpend(int timeSpend) {
            this.timeSpend = timeSpend;
        }
        //面向
        public int getFaceDirection() {
            return FaceDirection;
        }
        public void setFaceDirection(int faceDirection) {
            FaceDirection = faceDirection;
        }
        //转向
        public Move getDirection() {
            return direction;
        }
        public void setDirection(Move direction) {
            this.direction = direction;
        }
        //输出
        public String toString(){
            return "汽车"+ "到达["+position[0]+","
                    +position[1]+"]处"
                    +",用时为"+timeSpend
                    +",当前面向为:"+FaceDirection
                    +",当前行动状态为"+direction+"。";
        }

    }

⑥全局变量

 public static int shorttime =  Integer.MAX_VALUE;
 public static int shortesPassTime = Integer.MAX_VALUE;

三、运行结果

1.运行截图

含红绿灯的街道车辆从起点到终点的最短时间(华为od机考题)_第3张图片

2.带数据分析的运行结果


请输入车辆通过每格街道需要的时间timePerRoad[0,600]:
2
时间timePerRoad:2,设置成功!
请输入街道的长n和宽m[1,9]:
3
2
街道长n:3,宽m:2,设置成功!
请输入n*m 个街口的交通灯周期T(=lights[row][col])[0,120]:
1 2 3 4 5 6
位置[0][0]处的交通灯时间T:1,设置成功!
位置[0][1]处的交通灯时间T:2,设置成功!
位置[1][0]处的交通灯时间T:3,设置成功!
位置[1][1]处的交通灯时间T:4,设置成功!
位置[2][0]处的交通灯时间T:5,设置成功!
位置[2][1]处的交通灯时间T:6,设置成功!
交通灯周期设置成功:
[1, 2]
[3, 4]
[5, 6]
请输入起点的行号rowStart:
0
请输入起点的列号colStart:
0
请输入终点的行号rowEnd:
2
请输入终点的列号colEnd:
1
汽车到达[0,0]处,用时为0,当前面向为:-1,当前行动状态为NoMoveDirection。
0 0 0 -1 NoMoveDirection
面向为:0,转向为:GoStraight
面向为:1,转向为:GoStraight
面向为:2,转向为:GoStraight
面向为:3,转向为:GoStraight

取值进入循环了:0 0 0 0 GoStraight
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:GoStraight
当前用时为:0,当前面向为:0,此时的目标面向i为0。为了从当前位置[0,0]到下个位置[0,1]需要直走。
从当前位置[0,0]到下个位置[0,1],需要等待2,加上行走用时:2,直走后面向为0,所用时间为:4
入列传值检查:[0,1],4 GoStraight 0
newSpot传值检验:到达[0,1]后,当前动点的状态:用时:4,转向:GoStraight,面向:0
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:GoStraight
当前用时为:0,当前面向为:0,此时的目标面向i为1。为了从当前位置[0,0]到下个位置[1,0]需要右转。
从当前位置[0,0]到下个位置[1,0],无需等待,加上行走用时:2,右转后面向为1,所用时间为:2
入列传值检查:[1,0],2 TurnRight 1
newSpot传值检验:到达[1,0]后,当前动点的状态:用时:2,转向:TurnRight,面向:1
2 2147483647
0 ===-1
-1 ===0

取值进入循环了:0 0 0 3 GoStraight
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:GoStraight
当前用时为:0,当前面向为:3,此时的目标面向i为0。为了从当前位置[0,0]到下个位置[0,1]需要右转。
从当前位置[0,0]到下个位置[0,1],无需等待,加上行走用时:2,右转后面向为0,所用时间为:2
入列传值检查:[0,1],2 TurnRight 0
newSpot传值检验:到达[0,1]后,当前动点的状态:用时:2,转向:TurnRight,面向:0
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:GoStraight
只能转一次,此次不记录
0 ===-1
-1 ===0

取值进入循环了:0 0 0 2 GoStraight
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:GoStraight
只能转一次,此次不记录
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:GoStraight
当前用时为:0,当前面向为:2,此时的目标面向i为1。为了从当前位置[0,0]到下个位置[1,0]需要左转。
从当前位置[0,0]到下个位置[1,0],需要等待3,加上行走用时:2,左转后面向为1,所用时间为:5
入列传值检查:[1,0],5 TurnLeft 1
newSpot传值检验:到达[1,0]后,当前动点的状态:用时:5,转向:TurnLeft,面向:1
2 2147483647
0 ===-1
-1 ===0

取值进入循环了:0 0 0 1 GoStraight
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:GoStraight
当前用时为:0,当前面向为:1,此时的目标面向i为0。为了从当前位置[0,0]到下个位置[0,1]需要左转。
从当前位置[0,0]到下个位置[0,1],需要等待2,加上行走用时:2,左转后面向为0,所用时间为:4
入列传值检查:[0,1],4 TurnLeft 0
newSpot传值检验:到达[0,1]后,当前动点的状态:用时:4,转向:TurnLeft,面向:0
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:GoStraight
当前用时为:0,当前面向为:1,此时的目标面向i为1。为了从当前位置[0,0]到下个位置[1,0]需要直走。
从当前位置[0,0]到下个位置[1,0],需要等待3,加上行走用时:2,直走后面向为1,所用时间为:5
入列传值检查:[1,0],5 GoStraight 1
newSpot传值检验:到达[1,0]后,当前动点的状态:用时:5,转向:GoStraight,面向:1
2 2147483647
0 ===-1
-1 ===0

取值进入循环了:1 0 2 1 TurnRight
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:TurnRight
当前用时为:2,当前面向为:1,此时的目标面向i为0。为了从当前位置[1,0]到下个位置[1,1]需要左转。
从当前位置[1,0]到下个位置[1,1],需要等待4,加上行走用时:2,左转后面向为0,所用时间为:8
入列传值检查:[1,1],8 TurnLeft 0
newSpot传值检验:到达[1,1]后,当前动点的状态:用时:8,转向:TurnLeft,面向:0
2 2147483647
2 ===0
我是在边界内的下一个可移动点的坐标:[2,0],当前的转向为:TurnRight
当前用时为:2,当前面向为:1,此时的目标面向i为1。为了从当前位置[1,0]到下个位置[2,0]需要直走。
从当前位置[1,0]到下个位置[2,0],需要等待5,加上行走用时:2,直走后面向为1,所用时间为:9
入列传值检查:[2,0],9 GoStraight 1
newSpot传值检验:到达[2,0]后,当前动点的状态:用时:9,转向:GoStraight,面向:1
2 2147483647
1 ===-1
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:TurnRight
只能转一次,此次不记录

取值进入循环了:0 1 2 0 TurnRight
0 ===2
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:TurnRight
当前用时为:2,当前面向为:0,此时的目标面向i为1。为了从当前位置[0,1]到下个位置[1,1]需要右转。
从当前位置[0,1]到下个位置[1,1],无需等待,加上行走用时:2,右转后面向为1,所用时间为:4
入列传值检查:[1,1],4 TurnRight 1
newSpot传值检验:到达[1,1]后,当前动点的状态:用时:4,转向:TurnRight,面向:1
2 2147483647
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:TurnRight
只能转一次,此次不记录
-1 ===1

取值进入循环了:0 1 4 0 TurnLeft
0 ===2
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:TurnLeft
当前用时为:4,当前面向为:0,此时的目标面向i为1。为了从当前位置[0,1]到下个位置[1,1]需要右转。
从当前位置[0,1]到下个位置[1,1],无需等待,加上行走用时:2,右转后面向为1,所用时间为:6
入列传值检查:[1,1],6 TurnRight 1
newSpot传值检验:到达[1,1]后,当前动点的状态:用时:6,转向:TurnRight,面向:1
2 2147483647
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:TurnLeft
只能转一次,此次不记录
-1 ===1

取值进入循环了:0 1 4 0 GoStraight
0 ===2
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:GoStraight
当前用时为:4,当前面向为:0,此时的目标面向i为1。为了从当前位置[0,1]到下个位置[1,1]需要右转。
从当前位置[0,1]到下个位置[1,1],无需等待,加上行走用时:2,右转后面向为1,所用时间为:6
入列传值检查:[1,1],6 TurnRight 1
newSpot传值检验:到达[1,1]后,当前动点的状态:用时:6,转向:TurnRight,面向:1
2 2147483647
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:GoStraight
只能转一次,此次不记录
-1 ===1

取值进入循环了:1 0 5 1 GoStraight
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:GoStraight
当前用时为:5,当前面向为:1,此时的目标面向i为0。为了从当前位置[1,0]到下个位置[1,1]需要左转。
从当前位置[1,0]到下个位置[1,1],需要等待4,加上行走用时:2,左转后面向为0,所用时间为:11
入列传值检查:[1,1],11 TurnLeft 0
newSpot传值检验:到达[1,1]后,当前动点的状态:用时:11,转向:TurnLeft,面向:0
2 2147483647
2 ===0
我是在边界内的下一个可移动点的坐标:[2,0],当前的转向为:GoStraight
当前用时为:5,当前面向为:1,此时的目标面向i为1。为了从当前位置[1,0]到下个位置[2,0]需要直走。
从当前位置[1,0]到下个位置[2,0],需要等待5,加上行走用时:2,直走后面向为1,所用时间为:12
入列传值检查:[2,0],12 GoStraight 1
newSpot传值检验:到达[2,0]后,当前动点的状态:用时:12,转向:GoStraight,面向:1
2 2147483647
1 ===-1
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:GoStraight
只能转一次,此次不记录

取值进入循环了:1 0 5 1 TurnLeft
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:TurnLeft
当前用时为:5,当前面向为:1,此时的目标面向i为0。为了从当前位置[1,0]到下个位置[1,1]需要左转。
从当前位置[1,0]到下个位置[1,1],需要等待4,加上行走用时:2,左转后面向为0,所用时间为:11
入列传值检查:[1,1],11 TurnLeft 0
newSpot传值检验:到达[1,1]后,当前动点的状态:用时:11,转向:TurnLeft,面向:0
2 2147483647
2 ===0
我是在边界内的下一个可移动点的坐标:[2,0],当前的转向为:TurnLeft
当前用时为:5,当前面向为:1,此时的目标面向i为1。为了从当前位置[1,0]到下个位置[2,0]需要直走。
从当前位置[1,0]到下个位置[2,0],需要等待5,加上行走用时:2,直走后面向为1,所用时间为:12
入列传值检查:[2,0],12 GoStraight 1
newSpot传值检验:到达[2,0]后,当前动点的状态:用时:12,转向:GoStraight,面向:1
2 2147483647
1 ===-1
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:TurnLeft
只能转一次,此次不记录

取值进入循环了:1 1 4 1 TurnRight
1 ===2
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:TurnRight
当前用时为:4,当前面向为:1,此时的目标面向i为1。为了从当前位置[1,1]到下个位置[2,1]需要直走。
从当前位置[1,1]到下个位置[2,1],需要等待6,加上行走用时:2,直走后面向为1,所用时间为:12
入列传值检查:[2,1],12 GoStraight 1
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:12,转向:GoStraight,面向:1
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:TurnRight
当前用时为:4,当前面向为:1,此时的目标面向i为2。为了从当前位置[1,1]到下个位置[1,0]需要右转。
从当前位置[1,1]到下个位置[1,0],无需等待,加上行走用时:2,右转后面向为2,所用时间为:6
入列传值检查:[1,0],6 TurnRight 2
newSpot传值检验:到达[1,0]后,当前动点的状态:用时:6,转向:TurnRight,面向:2
2 2147483647
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:TurnRight
只能转一次,此次不记录

取值进入循环了:1 1 6 1 TurnRight
1 ===2
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:TurnRight
当前用时为:6,当前面向为:1,此时的目标面向i为1。为了从当前位置[1,1]到下个位置[2,1]需要直走。
从当前位置[1,1]到下个位置[2,1],需要等待6,加上行走用时:2,直走后面向为1,所用时间为:14
入列传值检查:[2,1],14 GoStraight 1
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:14,转向:GoStraight,面向:1
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:TurnRight
当前用时为:6,当前面向为:1,此时的目标面向i为2。为了从当前位置[1,1]到下个位置[1,0]需要右转。
从当前位置[1,1]到下个位置[1,0],无需等待,加上行走用时:2,右转后面向为2,所用时间为:8
入列传值检查:[1,0],8 TurnRight 2
newSpot传值检验:到达[1,0]后,当前动点的状态:用时:8,转向:TurnRight,面向:2
2 2147483647
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:TurnRight
只能转一次,此次不记录

取值进入循环了:1 1 6 1 TurnRight
1 ===2
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:TurnRight
当前用时为:6,当前面向为:1,此时的目标面向i为1。为了从当前位置[1,1]到下个位置[2,1]需要直走。
从当前位置[1,1]到下个位置[2,1],需要等待6,加上行走用时:2,直走后面向为1,所用时间为:14
入列传值检查:[2,1],14 GoStraight 1
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:14,转向:GoStraight,面向:1
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:TurnRight
当前用时为:6,当前面向为:1,此时的目标面向i为2。为了从当前位置[1,1]到下个位置[1,0]需要右转。
从当前位置[1,1]到下个位置[1,0],无需等待,加上行走用时:2,右转后面向为2,所用时间为:8
入列传值检查:[1,0],8 TurnRight 2
newSpot传值检验:到达[1,0]后,当前动点的状态:用时:8,转向:TurnRight,面向:2
2 2147483647
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:TurnRight
只能转一次,此次不记录

取值进入循环了:1 1 8 0 TurnLeft
1 ===2
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:TurnLeft
当前用时为:8,当前面向为:0,此时的目标面向i为1。为了从当前位置[1,1]到下个位置[2,1]需要右转。
从当前位置[1,1]到下个位置[2,1],无需等待,加上行走用时:2,右转后面向为1,所用时间为:10
入列传值检查:[2,1],10 TurnRight 1
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:10,转向:TurnRight,面向:1
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:TurnLeft
只能转一次,此次不记录
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:TurnLeft
当前用时为:8,当前面向为:0,此时的目标面向i为3。为了从当前位置[1,1]到下个位置[0,1]需要左转。
从当前位置[1,1]到下个位置[0,1],需要等待2,加上行走用时:2,左转后面向为3,所用时间为:12
入列传值检查:[0,1],12 TurnLeft 3
newSpot传值检验:到达[0,1]后,当前动点的状态:用时:12,转向:TurnLeft,面向:3
2 2147483647

取值进入循环了:2 0 9 1 GoStraight
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:GoStraight
当前用时为:9,当前面向为:1,此时的目标面向i为0。为了从当前位置[2,0]到下个位置[2,1]需要左转。
从当前位置[2,0]到下个位置[2,1],需要等待6,加上行走用时:2,左转后面向为0,所用时间为:17
入列传值检查:[2,1],17 TurnLeft 0
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:17,转向:TurnLeft,面向:0
2 2147483647
3 ===0
2 ===-1
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:GoStraight
只能转一次,此次不记录

取值进入循环了:1 1 11 0 TurnLeft
1 ===2
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:TurnLeft
当前用时为:11,当前面向为:0,此时的目标面向i为1。为了从当前位置[1,1]到下个位置[2,1]需要右转。
从当前位置[1,1]到下个位置[2,1],无需等待,加上行走用时:2,右转后面向为1,所用时间为:13
入列传值检查:[2,1],13 TurnRight 1
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:13,转向:TurnRight,面向:1
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:TurnLeft
只能转一次,此次不记录
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:TurnLeft
当前用时为:11,当前面向为:0,此时的目标面向i为3。为了从当前位置[1,1]到下个位置[0,1]需要左转。
从当前位置[1,1]到下个位置[0,1],需要等待2,加上行走用时:2,左转后面向为3,所用时间为:15
入列传值检查:[0,1],15 TurnLeft 3
newSpot传值检验:到达[0,1]后,当前动点的状态:用时:15,转向:TurnLeft,面向:3
2 2147483647

取值进入循环了:1 1 11 0 TurnLeft
1 ===2
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:TurnLeft
当前用时为:11,当前面向为:0,此时的目标面向i为1。为了从当前位置[1,1]到下个位置[2,1]需要右转。
从当前位置[1,1]到下个位置[2,1],无需等待,加上行走用时:2,右转后面向为1,所用时间为:13
入列传值检查:[2,1],13 TurnRight 1
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:13,转向:TurnRight,面向:1
2 2147483647
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:TurnLeft
只能转一次,此次不记录
0 ===1
我是在边界内的下一个可移动点的坐标:[0,1],当前的转向为:TurnLeft
当前用时为:11,当前面向为:0,此时的目标面向i为3。为了从当前位置[1,1]到下个位置[0,1]需要左转。
从当前位置[1,1]到下个位置[0,1],需要等待2,加上行走用时:2,左转后面向为3,所用时间为:15
入列传值检查:[0,1],15 TurnLeft 3
newSpot传值检验:到达[0,1]后,当前动点的状态:用时:15,转向:TurnLeft,面向:3
2 2147483647

取值进入循环了:2 0 12 1 GoStraight
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:GoStraight
当前用时为:12,当前面向为:1,此时的目标面向i为0。为了从当前位置[2,0]到下个位置[2,1]需要左转。
从当前位置[2,0]到下个位置[2,1],需要等待6,加上行走用时:2,左转后面向为0,所用时间为:20
入列传值检查:[2,1],20 TurnLeft 0
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:20,转向:TurnLeft,面向:0
2 2147483647
3 ===0
2 ===-1
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:GoStraight
只能转一次,此次不记录

取值进入循环了:2 0 12 1 GoStraight
2 ===1
我是在边界内的下一个可移动点的坐标:[2,1],当前的转向为:GoStraight
当前用时为:12,当前面向为:1,此时的目标面向i为0。为了从当前位置[2,0]到下个位置[2,1]需要左转。
从当前位置[2,0]到下个位置[2,1],需要等待6,加上行走用时:2,左转后面向为0,所用时间为:20
入列传值检查:[2,1],20 TurnLeft 0
newSpot传值检验:到达[2,1]后,当前动点的状态:用时:20,转向:TurnLeft,面向:0
2 2147483647
3 ===0
2 ===-1
1 ===0
我是在边界内的下一个可移动点的坐标:[1,0],当前的转向为:GoStraight
只能转一次,此次不记录

取值进入循环了:1 0 6 2 TurnRight
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:TurnRight
只能转一次,此次不记录
2 ===0
我是在边界内的下一个可移动点的坐标:[2,0],当前的转向为:TurnRight
当前用时为:6,当前面向为:2,此时的目标面向i为1。为了从当前位置[1,0]到下个位置[2,0]需要左转。
从当前位置[1,0]到下个位置[2,0],需要等待5,加上行走用时:2,左转后面向为1,所用时间为:13
入列传值检查:[2,0],13 TurnLeft 1
newSpot传值检验:到达[2,0]后,当前动点的状态:用时:13,转向:TurnLeft,面向:1
2 2147483647
1 ===-1
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:TurnRight
当前用时为:6,当前面向为:2,此时的目标面向i为3。为了从当前位置[1,0]到下个位置[0,0]需要右转。
从当前位置[1,0]到下个位置[0,0],无需等待,加上行走用时:2,右转后面向为3,所用时间为:8
入列传值检查:[0,0],8 TurnRight 3
newSpot传值检验:到达[0,0]后,当前动点的状态:用时:8,转向:TurnRight,面向:3
2 2147483647

取值进入循环了:1 0 8 2 TurnRight
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:TurnRight
只能转一次,此次不记录
2 ===0
我是在边界内的下一个可移动点的坐标:[2,0],当前的转向为:TurnRight
当前用时为:8,当前面向为:2,此时的目标面向i为1。为了从当前位置[1,0]到下个位置[2,0]需要左转。
从当前位置[1,0]到下个位置[2,0],需要等待5,加上行走用时:2,左转后面向为1,所用时间为:15
入列传值检查:[2,0],15 TurnLeft 1
newSpot传值检验:到达[2,0]后,当前动点的状态:用时:15,转向:TurnLeft,面向:1
2 2147483647
1 ===-1
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:TurnRight
当前用时为:8,当前面向为:2,此时的目标面向i为3。为了从当前位置[1,0]到下个位置[0,0]需要右转。
从当前位置[1,0]到下个位置[0,0],无需等待,加上行走用时:2,右转后面向为3,所用时间为:10
入列传值检查:[0,0],10 TurnRight 3
newSpot传值检验:到达[0,0]后,当前动点的状态:用时:10,转向:TurnRight,面向:3
2 2147483647

取值进入循环了:1 0 8 2 TurnRight
1 ===1
我是在边界内的下一个可移动点的坐标:[1,1],当前的转向为:TurnRight
只能转一次,此次不记录
2 ===0
我是在边界内的下一个可移动点的坐标:[2,0],当前的转向为:TurnRight
当前用时为:8,当前面向为:2,此时的目标面向i为1。为了从当前位置[1,0]到下个位置[2,0]需要左转。
从当前位置[1,0]到下个位置[2,0],需要等待5,加上行走用时:2,左转后面向为1,所用时间为:15
入列传值检查:[2,0],15 TurnLeft 1
newSpot传值检验:到达[2,0]后,当前动点的状态:用时:15,转向:TurnLeft,面向:1
2 2147483647
1 ===-1
0 ===0
我是在边界内的下一个可移动点的坐标:[0,0],当前的转向为:TurnRight
当前用时为:8,当前面向为:2,此时的目标面向i为3。为了从当前位置[1,0]到下个位置[0,0]需要右转。
从当前位置[1,0]到下个位置[0,0],无需等待,加上行走用时:2,右转后面向为3,所用时间为:10
入列传值检查:[0,0],10 TurnRight 3
newSpot传值检验:到达[0,0]后,当前动点的状态:用时:10,转向:TurnRight,面向:3
2 2147483647

取值进入循环了:2 1 10 1 TurnRight
1 10
3 10
3 10
3 10
最短是shortesPassTime 10
车辆经过两个街口的最短时间为:10

进程已结束,退出代码为 0

3.运行结果分析

含红绿灯的街道车辆从起点到终点的最短时间(华为od机考题)_第4张图片

4.含数据分析的完整代码

import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;

public class test22 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        //输入时间周期数组
        System.out.println("请输入车辆通过每格街道需要的时间timePerRoad[0,600]:");
        int timePerRoad = sc.nextInt();
        if (timePerRoad>=0&&timePerRoad<=600){
            System.out.println("时间timePerRoad:"+timePerRoad+",设置成功!");
        }else {
            System.out.println("非法输入!");
            return;
        }
        //输入棋盘长宽
        System.out.println("请输入街道的长n和宽m[1,9]:");
        int n = sc.nextInt();
        int m = sc.nextInt();
        if (n>=1 && n<=9 && m>=1 && m<=9){
            System.out.println("街道长n:"+n+",宽m:"+m+",设置成功!");
        }else {
            System.out.println("非法输入!");
            return;
        }
        //输入交通灯周期数组
        System.out.println("请输入n*m 个街口的交通灯周期T(=lights[row][col])[0,120]:");
        int[][] lights = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                lights[i][j] = sc.nextInt();
                if (lights[i][j]>=0&&lights[i][j]<=120){
                    System.out.println("位置["+i+"]["+j+"]处的交通灯时间T:"+lights[i][j]+",设置成功!");
                }else {
                    System.out.println("非法输入!");
                    return;
                }
            }
        }
        System.out.println("交通灯周期设置成功:");
        for (int[] row : lights) {
            System.out.println(Arrays.toString(row));
        }
        //输入起止街口的坐标
        System.out.println("请输入起点的行号rowStart:");
        int rowStart = sc.nextInt();
        System.out.println("请输入起点的列号colStart:");
        int colStart = sc.nextInt();
        System.out.println("请输入终点的行号rowEnd:");
        int rowEnd = sc.nextInt();
        System.out.println("请输入终点的列号colEnd:");
        int colEnd = sc.nextInt();

        //int time = calcTime(lights,timePerRoad,rowStart,colStart,rowEnd,colEnd);
        System.out.println("车辆经过两个街口的最短时间为:"+calcTime(lights,timePerRoad,rowStart,colStart,rowEnd,colEnd));//从起点到终点的最短时间
    }


    public static int[][] DIRECTION = {
            {0,1},//上up0
            {1,0},//右right1
            {0,-1},//下down2
            {-1,0}//左left3
    };


    //注意边界!!!
    public static int shortesPassTime = Integer.MAX_VALUE;
    private static int calcTime(int[][] lights, int timePerRoad, int rowStart, int colStart, int rowEnd, int colEnd) {

        //----------------------------------
        int n = lights.length;
        int m = lights[0].length;
        //
        PriorityQueue pqMoveSpot = new PriorityQueue<>(
                Comparator.comparingInt(MoveSpot::getTimeSpend));
        MoveSpot start = new MoveSpot(rowStart,colStart,0,-1, MoveSpot.Move.NoMoveDirection);
        pqMoveSpot.add(start);
        //打印检查-------------
        for (MoveSpot move : pqMoveSpot) {
            System.out.println(move);
        }
        //--------------------

        //当优先队列不为空时,当前只存了start点
        MoveSpot startMoveSpot = pqMoveSpot.poll();
        //赋值
        int startx = startMoveSpot.position[0];//row
        int starty = startMoveSpot.position[1];//col
        int startTime = startMoveSpot.timeSpend;//时间
        int startfaceDir = startMoveSpot.FaceDirection;//面向
        MoveSpot.Move startmoveDir = startMoveSpot.direction;//转向
        //打印检验
        System.out.println(startx + " " + starty + " " + startTime+" "+startfaceDir+" "+startmoveDir);
        //起点初始化,无面向无转向,面向可为可上下左右
        if (startfaceDir==-1&&startmoveDir== MoveSpot.Move.NoMoveDirection){
            for (int i=0;i<4;i++){
                //上
                if (i==0){
                    startfaceDir = 0;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    System.out.println("面向为:"+startfaceDir+",转向为:"+startmoveDir);
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
                //右
                if (i==1){
                    startfaceDir = 1;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    System.out.println("面向为:"+startfaceDir+",转向为:"+startmoveDir);
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
                //下
                if (i==2){
                    startfaceDir = 2;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    System.out.println("面向为:"+startfaceDir+",转向为:"+startmoveDir);
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
                //左
                if (i==3){
                    startfaceDir = 3;//将当前的面向改为上
                    //刚出发不考虑转向,随便设置,转向是后期根据面向改变进行判断的,可不设置
                    startmoveDir = MoveSpot.Move.GoStraight;
                    System.out.println("面向为:"+startfaceDir+",转向为:"+startmoveDir);
                    pqMoveSpot.offer(new MoveSpot(rowStart,colStart,0,startfaceDir, startmoveDir));
                }
            }
        }
        /*
            for (int i=0;i<4;i++){
                System.out.println("看看初始化好没"+pqMoveSpot.poll());
                }
         */

        shortesPassTime=findMoveRoad(pqMoveSpot,rowEnd,colEnd,lights,timePerRoad);//=======================调用
        System.out.println("最短是shortesPassTime "+shortesPassTime);
       /* if (!pqMoveSpot.isEmpty()){
        ///    shortesPassTime=pqMoveSpot.peek().getTimeSpend();
        }*/
        //时间=路线经过格子数量*tPR+经过格子的灯周期累计(右转=0/直左=T) 算路线?根据累积量来?
        //起点终点时间不计算
        return shortesPassTime;
    }
    public static int shorttime =  Integer.MAX_VALUE;;
    private static int findMoveRoad(PriorityQueue pqMoveSpot,int rowEnd,int colEnd,int[][] lights,int timePerRoad) {
        int n = lights.length;
        int m = lights[0].length;
        PriorityQueue newpqMoveSpot = new PriorityQueue<>(
                Comparator.comparingInt(MoveSpot::getTimeSpend));
        while (!pqMoveSpot.isEmpty()) {
            //从队列中拿出放入当前动点
            MoveSpot currentMoveSpot = pqMoveSpot.poll();
            //赋值
            int x = currentMoveSpot.position[0];//row
            int y = currentMoveSpot.position[1];//col
            int currentTime = currentMoveSpot.timeSpend;//时间
            int currentfaceDir = currentMoveSpot.FaceDirection;//面向
            MoveSpot.Move currentmoveDir = currentMoveSpot.direction;//转向
            //打印检验
            System.out.println("\n取值进入循环了:" + x + " " + y + " " + currentTime + " " + currentfaceDir + " " + currentmoveDir);

            //当到了终点就返回时间
            if (x == rowEnd && y == colEnd) {
                System.out.println("1 "+currentTime);
                return currentTime;
            }

            //遍历四个方向
            for (int i = 0; i < 4; i++) {
                x = currentMoveSpot.position[0];//row
                y = currentMoveSpot.position[1];//col
                currentTime = currentMoveSpot.timeSpend;//时间
                currentfaceDir = currentMoveSpot.FaceDirection;//面向
                currentmoveDir = currentMoveSpot.direction;//转向
                //eg:i=0,取DIRECTION[0][0]与DIRECTION[0][1]即向上(x+0,y+1)
                int newX = x + DIRECTION[i][0];
                int newY = y + DIRECTION[i][1];
                System.out.println(newX + " ===" + newY);
                //在边界内
                if (newX >= 0 && newX < n && newY >= 0 && newY < m) {
                    MoveSpot.Move movedirection = currentmoveDir;
                    System.out.println("我是在边界内的下一个可移动点的坐标:[" + newX + "," + newY + "],当前的转向为:" + movedirection);
                    if (currentfaceDir == i) {//面向一致
                        currentTime = currentMoveSpot.timeSpend;
                        System.out.println("当前用时为:" + currentTime + ",当前面向为:" + currentfaceDir + ",此时的目标面向i为" + i + "。为了从当前位置[" + x + "," + y + "]到下个位置[" + newX + "," + newY + "]需要直走。");
                        movedirection = MoveSpot.Move.GoStraight;
                        currentTime = currentTime + lights[newX][newY] + timePerRoad;//直行时间为交通灯等待时间+行走时间
                        currentfaceDir = i;
                        System.out.println("从当前位置[" + x + "," + y + "]到下个位置[" + newX + "," + newY + "],需要等待" + lights[newX][newY] + ",加上行走用时:" + timePerRoad + ",直走后面向为" + currentfaceDir + ",所用时间为:" + currentTime);
                    } else {//面向不一致
                        if (Math.abs(currentfaceDir - i) == 2) {//若需要转两次
                            System.out.println("只能转一次,此次不记录");
                            continue;
                        } else {
                            //01 12 23 30右转
                            if (i - currentfaceDir == 1 || (currentfaceDir == 3 && i == 0)) {
                                currentTime = currentMoveSpot.timeSpend;
                                System.out.println("当前用时为:" + currentTime + ",当前面向为:" + currentfaceDir + ",此时的目标面向i为" + i + "。为了从当前位置[" + x + "," + y + "]到下个位置[" + newX + "," + newY + "]需要右转。");
                                movedirection = MoveSpot.Move.TurnRight;
                                currentTime = currentTime + timePerRoad;//右转时间为行走时间
                                currentfaceDir = i;
                                System.out.println("从当前位置[" + x + "," + y + "]到下个位置[" + newX + "," + newY + "],无需等待,加上行走用时:" + timePerRoad + ",右转后面向为" + currentfaceDir + ",所用时间为:" + currentTime);
                            }
                            //03 10 21 32左转
                            else if (currentfaceDir - i == 1 || (currentfaceDir == 0 && i == 3)) {
                                currentTime = currentMoveSpot.timeSpend;
                                System.out.println("当前用时为:" + currentTime + ",当前面向为:" + currentfaceDir + ",此时的目标面向i为" + i + "。为了从当前位置[" + x + "," + y + "]到下个位置[" + newX + "," + newY + "]需要左转。");
                                movedirection = MoveSpot.Move.TurnLeft;
                                currentTime = currentTime + lights[newX][newY] + timePerRoad;//左转时间为交通灯等待时间+行走时间
                                currentfaceDir = i;
                                System.out.println("从当前位置[" + x + "," + y + "]到下个位置[" + newX + "," + newY + "],需要等待" + lights[newX][newY] + ",加上行走用时:" + timePerRoad + ",左转后面向为" + currentfaceDir + ",所用时间为:" + currentTime);
                            }
                        }
                    }
                    //加入队列
                    System.out.println("入列传值检查:[" + newX + "," + newY + "]," + currentTime + " " + movedirection + " " + currentfaceDir);
                    MoveSpot newSpot = new MoveSpot(newX, newY, currentTime, currentfaceDir, movedirection);
                    newSpot.position[0] = newX;
                    newSpot.position[1] = newY;
                    newSpot.timeSpend = currentTime;
                    newSpot.direction = movedirection;
                    newSpot.FaceDirection = currentfaceDir;
                    newpqMoveSpot.offer(newSpot);
                    System.out.println("newSpot传值检验:到达[" + newSpot.position[0] + "," + newSpot.position[1] + "]后,当前动点的状态:用时:" + newSpot.timeSpend + ",转向:" + newSpot.direction + ",面向:" + newSpot.FaceDirection);
                    //shorttime = newpqMoveSpot.peek().getTimeSpend();
                    System.out.println("2 "+shorttime);
                }//边界内判断
            }//四方向循环
        }
        /*
        for (int i = 0; i < 10; i++) {
            System.out.println("newpq检查:"+newpqMoveSpot.poll());
        }
         */
        shorttime = findMoveRoad(newpqMoveSpot, rowEnd, colEnd, lights, timePerRoad);
        System.out.println("3 "+shorttime);
        return shorttime;
    }

    //定义一个动点类
    public static class MoveSpot {
        private int[] position = new int[2];//位置 {row,col}
        private int timeSpend;//用时
        private int FaceDirection;//面向
        private Move direction;//转向

        public class FaceDirection{
            public static final int NULL = -1;
            public static final int UP = 0;
            public static final int DOWN = 1;
            public static final int LEFT = 2;
            public static final int RIGHT = 3;
        }
        //转向枚举
        public enum Move {
            NoMoveDirection,GoStraight,TurnLeft,TurnRight;
        }

        //构造函数
        public MoveSpot(int row , int col , int timeSpend, int faceDirection,Move direction) {
            this.position[0] = row;//位置行列
            this.position[1] = col;
            this.timeSpend = timeSpend;
            this.FaceDirection = faceDirection;
            this.direction = direction;
        }

        //方法
        //位置
        public int[] getPosition() {
            return position;
        }
        public void setPosition(int row, int col) {
            this.position[0] = row;
            this.position[1] = col;
        }
        //时间
        public int getTimeSpend() {
            return timeSpend;
        }
        public void setTimeSpend(int timeSpend) {
            this.timeSpend = timeSpend;
        }
        //面向
        public int getFaceDirection() {
            return FaceDirection;
        }
        public void setFaceDirection(int faceDirection) {
            FaceDirection = faceDirection;
        }
        //转向
        public Move getDirection() {
            return direction;
        }
        public void setDirection(Move direction) {
            this.direction = direction;
        }
        //输出
        public String toString(){
            return "汽车"+ "到达["+position[0]+","
                    +position[1]+"]处"
                    +",用时为"+timeSpend
                    +",当前面向为:"+FaceDirection
                    +",当前行动状态为"+direction+"。";
        }


    }

}

你可能感兴趣的:(华为od机考,华为od,算法,java)