迷宫的深度广度算法

解决杭电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;
    }
}

 

 

 

 

 

  

 

 

 

  

    

 

    

 

posted @ 2017-09-23 18:43  张秀杰  阅读(455)  评论(0编辑  收藏  举报