迷宫的深度广度算法
Posted 夜空中最亮的星
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迷宫的深度广度算法相关的知识,希望对你有一定的参考价值。
解决杭电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; } }
以上是关于迷宫的深度广度算法的主要内容,如果未能解决你的问题,请参考以下文章