• 迷宫的深度广度算法


    解决杭电1010题目的意思就是求从开始点到终点的经过的边的个数和(即经过的总的点数减去一)等于给定的T

           对于迷宫问题,由于所求的路径不一定是最短的,所以不适合用广度优先遍历。

    基础知识

    奇偶剪枝:t表示非最短路径走的步数,开始点为(sx,sy),结束点位(ex,ey) 那么从开始点到结束点的最短路径为 abs(ex-sx)+abs(ey-sy)  ,那么t-(abs(ex-sx)+abs(ey-sy))为非奇数,

    因为步数是成对出现上下,左右。

     还有一个修剪知识  假设 N行,M列矩阵中有walls个墙,其中t表示要求的路径长度,那么当N*M-walls<=t时,不存在通路。

      证明    当存在从开始点到终点的通路时,N*M=walls+1+1+value,其中value表示除开始和结束点外的所有可用点。而value+1+1-1>=t,从而value+1>=t

         从而 N*M-walls>=1+t ,所以当 N*M-wallls<=t时,不存在通路。

    广度优先遍历算法如图:

    package com.holdon.complete;
    
    import java.util.Scanner;
    
    //深度优先遍历,解决问题
    public class pro1010MN {
    
        public static char Maze[][];
        public static PointNMs move[] = { new PointNMs(1, 0), new PointNMs(0, -1),
                new PointNMs(-1, 0), new PointNMs(0, 1) };// 右,下,左,上
        public static PointNMs endPoint;
        public static PointNMs startPoint;
        // 用于剪枝 m*n-wall<=t表示不存在满足条件的情况
        public static int walls;// 表示墙的个数
        public static boolean sum_flage;
        public static int sum_seecond;
        public static int row;
        public static int column;
    
        public static void main(String[] args) {
    
            Scanner scanner = new Scanner(System.in);
            row = scanner.nextInt();
            column = scanner.nextInt();
            sum_seecond = scanner.nextInt();
            scanner.nextLine();// 吃掉换行符
            while (row != 0 && column != 0 && sum_seecond != 0) {
                InitData(row, column);
                for (int i = 1; i < row + 1; i++) {
                    String rowdatas = scanner.nextLine();
                    SetInputData(i, rowdatas);
                }
                boolean flage = true;
                if (row * column - walls <= sum_seecond)// 剪枝操作
                    flage = false;
                if (flage) {
                    Maze[startPoint.x][startPoint.y] = 'X';
                    MazeDepPath(startPoint.x, startPoint.y, 0);
                }
                if (flage && sum_flage)
                    System.out.println("YES");
                else
                    System.out.println("NO");
                row = scanner.nextInt();
                column = scanner.nextInt();
                sum_seecond = scanner.nextInt();
                scanner.nextLine();
            }
        }
    
        private static void MazeDepPath(int x, int y, int time) {
    
            if (x <= 0 || x > row || y <= 0 || y > column)//判断边界,少加这一条语句,会出现错误
                return;
            if (x == endPoint.x && y == endPoint.y && time == sum_seecond) {
                sum_flage = true;
                return;
            }
            if (sum_flage)
                return;
            int tempt = (sum_seecond - time)
                    - (Math.abs(x - endPoint.x) + Math.abs(y - endPoint.y));
            if (tempt < 0 || tempt % 2 == 1)//剪枝操作
                return;
    
            for (int i = 0; i < move.length; i++) {
                int xx = x + move[i].x;
                int yy = y + move[i].y;
                if (Maze[xx][yy] != 'X') {
                    Maze[xx][yy] = 'X';
                    MazeDepPath(xx, yy, time + 1);
                    Maze[xx][yy] = '.';
                    if (sum_flage)
                        return;
                }
    
            }
        }
    
        private static void InitData(int row, int column) {
            Maze = new char[row + 2][];
            walls = 0;
            sum_flage = false;
            for (int i = 0; i < row + 2; i++) {
                Maze[i] = new char[column + 2];
                // 制作一堵墙
                Maze[i][column + 1] = Maze[i][0] = 'X';
            }
            // 制作一堵墙
            for (int j = 0; j < column + 2; j++) {
                Maze[0][j] = Maze[row + 1][j] = 'X';
            }
        }
    
        private static void SetInputData(int i, String rowdatas) {
            // char字符数组
            char[] charArray = rowdatas.trim().toCharArray();
            for (int j = 0; j < charArray.length; j++) {
                Maze[i][j + 1] = charArray[j];
                if (charArray[j] == 'D')
                    endPoint = new PointNMs(i, j + 1);
                if (charArray[j] == 'S')
                    startPoint = new PointNMs(i, j + 1);
                if (charArray[j] == 'X')
                    walls++;
            }
        }
    }
    class PointNMs {
        int x;
        int y;
        public PointNMs(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public boolean isEqual(PointNMs a) {
            return (a.x == this.x && a.y == this.y) ? true : false;
        }
    }

    迷宫的广度优先遍历算法如下:找出起始点到终点的最短路径

    package com.holdon.complete;
    
    import java.util.ArrayDeque;
    import java.util.Scanner;
    import java.util.Stack;
    
    /*
     * 
     * 4 4 5
     S...
     ..X.
     ..XD
     ....
     Yes
     (1,1) 
     (1,2) 
     (2,2) 
     (3,2) 
     (4,2) 
     (4,3) 
     (4,4) 
     (3,4) 
     */
    //不能用广度优先遍历处理 ,因为路径不一定是最短的,但此遍历方法求出的是最短路径
    public class pro1010M {
        public static char Maze[][];
        public static PointNM pre[][];
        public static ArrayDeque<PointNM> qpoints;
        public static PointNM move[] = { new PointNM(1, 0), new PointNM(0, -1),
                new PointNM(-1, 0), new PointNM(0, 1) };// 右,下,左,上
        public static PointNM endPoint;
        public static PointNM startPoint;
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int row = scanner.nextInt();
            int column = scanner.nextInt();
            int sum_seecond = scanner.nextInt();
            scanner.nextLine();// 吃掉换行符
            while (row != 0 && column != 0 && sum_seecond != 0) {
                InitData(row, column);
                for (int i = 1; i < row + 1; i++) {
                    String rowdatas = scanner.nextLine();
                    SetInputData(i, rowdatas);
                }
                if (MazePath(row, column, endPoint, startPoint)
                        && PrintPath(endPoint, startPoint, sum_seecond))
                    System.out.println("YES");
                else
                    System.out.println("NO");
                row = scanner.nextInt();
                column = scanner.nextInt();
                sum_seecond = scanner.nextInt();
                scanner.nextLine();
            }
        }
        // 获取路径坐标序列
        private static boolean PrintPath(PointNM endPoint, PointNM startPoint,
                int sum_seecond) {
            Stack<PointNM> st = new Stack<PointNM>();
            while (!endPoint.isEqual(startPoint)) {
                st.push(endPoint);
                endPoint = pre[endPoint.x][endPoint.y];
            }
            st.push(startPoint);
            /*
             * while (!st.isEmpty()) { PointNM pop = st.pop();
             * System.out.println("(" + pop.x + "," + pop.y + ") "); }
             */
            return (sum_seecond - st.size() + 1) == 0 ? true : false;
        }
        // 获得数据路径,是否可行
        private static boolean MazePath(int row, int column, PointNM endPoint,
                PointNM startPoint) {
    
            if (endPoint.isEqual(startPoint))
                return true;
            qpoints.offer(startPoint);
            Maze[startPoint.x][startPoint.y] = 'X';
            while (!qpoints.isEmpty()) {
                PointNM nowPoint = qpoints.poll();
                for (int i = 0; i < move.length; i++) {// 每个方向广度遍历
                    if (nowPoint.x + move[i].x == endPoint.x
                            && nowPoint.y + move[i].y == endPoint.y) {
                        pre[endPoint.x][endPoint.y] = new PointNM(nowPoint.x,
                                nowPoint.y);
                        Maze[endPoint.x][endPoint.y] = 'X';
                        return true;
                    }
                    if (Maze[nowPoint.x + move[i].x][nowPoint.y + move[i].y] == '.') {
                        int x = nowPoint.x + move[i].x;
                        int y = nowPoint.y + move[i].y;
                        PointNM tempt = new PointNM(x, y);
                        pre[tempt.x][tempt.y] = new PointNM(nowPoint.x, nowPoint.y);
                        qpoints.offer(tempt);
                        Maze[x][y] = 'X';
                    }
                }
            }
            return false;
        }
        private static void SetInputData(int i, String rowdatas) {
            // char字符数组
            char[] charArray = rowdatas.trim().toCharArray();
            for (int j = 0; j < charArray.length; j++) {
                Maze[i][j + 1] = charArray[j];
                if (charArray[j] == 'D')
                    endPoint = new PointNM(i, j + 1);
                if (charArray[j] == 'S')
                    startPoint = new PointNM(i, j + 1);
            }
        }
        private static void InitData(int row, int column) {
            Maze = new char[row + 2][];
            pre = new PointNM[row + 2][];
            qpoints = new ArrayDeque<PointNM>();
            for (int i = 0; i < row + 2; i++) {
                Maze[i] = new char[column + 2];
                pre[i] = new PointNM[column + 2];
                // 制作一堵墙
                Maze[i][column + 1] = Maze[i][0] = 'X';
            }
            // 制作一堵墙
            for (int j = 0; j < column + 2; j++) {
                Maze[0][j] = Maze[row + 1][j] = 'X';
            }
        }
    }
    class PointNM {
        int x;
        int y;
    
        public PointNM(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public boolean isEqual(PointNM a) {
            return (a.x == this.x && a.y == this.y) ? true : false;
        }
    }

      

      

        

        

  • 相关阅读:
    redis分布式锁练习【我】
    自己写了个简单的redis分布式锁【我】
    高并发下的幂等策略分析
    Unity原厂讲师大解密
    Unity3D 多人协作开发 环境搭建 笔记(场景合并)
    Uni2D Unity4.3 2D Skeletal Animation
    2D Skeletal Animation Ready
    Unity Editor类常用方法
    右键菜单 GenericMenu
    Unity Editor Toolbar 编辑器扩展
  • 原文地址:https://www.cnblogs.com/09120912zhang/p/7582056.html
Copyright © 2020-2023  润新知