DFS (depth-first search) solution to the maze problem (with detailed notes) - java language

The following is an introduction to the solution of DFS to find the maze problem.
DFS is generally used to find the total number of paths from the starting point to the end point in the maze (BFS is generally used to find the shortest distance).
Let's take a classic example as an example to give you the template of the solution of DFS to find the maze problem. , there are detailed notes in the DFS algorithm in exercise 1, and there is no

Exercise 1: DFS_walk the character maze

Given a 2-dimensional maze with n rows and m columns, 'S' represents the starting point of the maze, 'T' represents the end point of the maze,
'#' represents the point that cannot be passed, and '.' represents the point that can be passed. You need to go from 'S' to 'T', you
can only walk up and down, left and right each time, and you can only enter the passable points, and each point can only be passed once.
Now you are asked to find out how many ways you can get through the maze.

Input format
The first line of input n,m (1≤n,m≤10) indicates the size of the maze.
Next, enter n lines of strings to represent the maze.

Output Format
Enter the number of ways to pass the maze.

/*
样例1:
输入
3 3
S..
.#.
..T

输出
2

样例2:
输入
5 5
S.###
#....
#.#.#
#.#.#
#.#.T

输出
1

样例3:
输入
6 6
...S..
.#.##.
......
...##.
.#.#..
.T....

输出
57
*/
import java.util.*;
public class DFS_走迷宫 {
    
    
	
	static int MAXV=1005;//最大顶点数
	
	static int n,m;		 //大小为n*m的地图
	static int[][] map2=new int[MAXV][MAXV]; //二选一,输入全为数字的地图
	static char[][] map=new char[MAXV][MAXV]; //二选一,输入含有字符的地图
	static int[][] vis=new int[MAXV][MAXV];	 //判定该点是否被访问过,0为未访问,1为访问过
	
	static int count=0;    //最终结果,count记录从起点到终点的路径条数
  //move数组的元素顺序,会决定遍历时的顺序,本例中顺序为“上下左右”
	static int move[][] = {
    
    {
    
    -1,0},{
    
    1,0},{
    
    0,-1},{
    
    0,1}};  
	
	//dfs算法
	public static void dfs(int x,int y) {
    
    	//x,y为当前访问的顶点坐标。DFS算法的参数列表列出的都是变化的参数
	//有时必须要不写check函数,而是通过dfs上来先检查if满足check条件,以便于后续的递归能继续进行
		
		//1、进来之后,要干什么
		vis[x][y]=1;
		//如果需要进行某些操作,就在这里进行
		
		//2、如果是终点,要干什么
		if(map[x][y]=='T') {
    
    	//出现目标态
			//做相应处理
			count++;
			return ;		//到达目标态,return返回上一层
		}
		
		//3、如果不是终点,要往后递归
		//下面对所有从(x,y)出发能达到的分支顶点进行枚举
		for(int i=0;i<4;i++) {
    
    
			//不能直接改变传入的参数x,y的值,要另设变量
			int nx=x+move[i][0];
			int ny=y+move[i][1];
//回溯法:在到达递归边界前的某层,由于一些事实导致已经不需要往任何一个子问题递归,就可以直接返回上一层
//回溯法:先判断,后递归   暴力法:先递归,后判断
			if(check(nx,ny)) {
    
      
				//满足条件,进行某种操作,并将新点进行递归
				dfs(nx,ny);	
//因为路径有多条,因此要将路线和标记恢复成访问前的状态,为遍历下一条路径时可能再次经过这个点做准备
				vis[nx][ny]=0;
			}
		}
	}
	
	//边界条件和约束条件的判断,条件由实际题目决定
	public static boolean check(int x,int y) {
    
    
		//注意是map[x][y]!='#',如果改成map[x][y]=='.',会忽略‘T’的情况
		if(x>=0&&y>=0&&x<n&&y<m&&map[x][y]!='#'&&vis[x][y]==0)
			return true;
		else return false;    //与约束条件冲突
	}
	
	
	public static void main(String[] args) {
    
    
		
		Scanner sc=new Scanner(System.in);
		
		//不能在n,m之前写int
		n=sc.nextInt();
		m=sc.nextInt();

		int x=0,y=0;
		for(int i=0;i<n;i++) {
    
    
			String s=sc.next();
			for(int j=0;j<s.length();j++) {
    
    
				if(s.charAt(j)=='S') {
    
    
					x=i;
					y=j;
				}
			}
			map[i]=s.toCharArray();
		}
		
		dfs(x,y);
		
//		如果跑完dfs后还需要进行其他某些操作,就在这里写
		System.out.println(count);
		sc.close();

	}

}


After getting the DFS template, practice the following classic example of the digital maze.
The data has been given in the question, and the result can be obtained by running it directly.

Exercise 2: DFS_Walking the Number Maze

Given an M*N matrix (two-dimensional array), use 0 and 1 to denote pathways and obstacles, respectively.
That is, 0 means access; 1 means obstacle.
Starting from the upper left corner of the matrix, you can only move the position to the right, down, left, and up each time, and you cannot walk diagonally.
Please give all routes from entrance to exit, the shortest route, the length of the shortest route.

import java.util.*;
public class DFS_走数字迷宫 {
    
    
	
	static int m,n,ans=0,l=0;
	static int[][] map = {
    
     
			{
    
    0, 0, 1, 1, 1, 1, 1, 1, 1},  
            {
    
    1, 0, 0, 0, 0, 0, 0, 0, 1},  
            {
    
    1, 0, 1, 1, 0, 1, 1, 0, 1},  
            {
    
    1, 0, 1, 0, 0, 1, 0, 0, 1},  
            {
    
    1, 0, 1, 0, 1, 0, 1, 0, 1},  
            {
    
    1, 0, 0, 0, 0, 0, 1, 0, 1},  
            {
    
    1, 1, 0, 1, 1, 0, 1, 1, 1},  
            {
    
    1, 0, 0, 0, 0, 0, 0, 0, 0},  
            {
    
    1, 1, 1, 1, 1, 1, 1, 1, 0}
			};
	static int v[][];
	
	static String path="";
	static String shortestpath="";
	static int move[][]= {
    
    {
    
    1,0},{
    
    0,1},{
    
    0,-1},{
    
    -1,0}};
	
	public static void dfs(int x,int y) {
    
    
		
		v[x][y]=1;
		l++;

		if(x==m-1&&y==n-1) {
    
    
			path=path+"("+x+","+y+")";
			
			if(shortestpath.length()==0||path.length()<shortestpath.length()) {
    
    
				shortestpath=path;
			}
			System.out.println(path);
			if(ans==0||l<ans) {
    
    
				ans=l;
			}
			return ;
		}

		//temp用于遍历完之后回退到本地址
		//temp的定义一定要在path增长后,否则会出错
		path=path+"("+x+","+y+")->";
		String temp=path;
		
		for(int i=0;i<4;i++) {
    
    
			int newx=x+move[i][0];
			int newy=y+move[i][1];
			if(check(newx,newy)) {
    
    
				dfs(newx,newy);
				//将路线和标记恢复成上一次的状态
				v[newx][newy]=0;
				path=temp;
				l--;
			}
		}
	}
	
	public static boolean check(int x,int y) {
    
    
		if(x>=0&&y>=0&&x<m&&y<n&&v[x][y]==0&&map[x][y]==0) {
    
    
			return true;
		}else return false;
	}
	
	public static void main(String[] args) {
    
    
		m=9;n=9;
		v=new int[m][n];
		dfs(0,0);
		System.out.println("最短路线为:"+shortestpath);
		System.out.println("最短路线长度为:"+ans);
		
//		(0,0)->(0,1)->(1,1)->(2,1)->(3,1)->(4,1)->(5,1)->(5,2)->(6,2)->(7,2)->(7,3)->(7,4)->(7,5)->(7,6)->(7,7)->(7,8)->(8,8)
//		(0,0)->(0,1)->(1,1)->(2,1)->(3,1)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)->(5,5)->(6,5)->(7,5)->(7,6)->(7,7)->(7,8)->(8,8)
//		(0,0)->(0,1)->(1,1)->(1,2)->(1,3)->(1,4)->(2,4)->(3,4)->(3,3)->(4,3)->(5,3)->(5,4)->(5,5)->(6,5)->(7,5)->(7,6)->(7,7)->(7,8)->(8,8)
//		(0,0)->(0,1)->(1,1)->(1,2)->(1,3)->(1,4)->(2,4)->(3,4)->(3,3)->(4,3)->(5,3)->(5,2)->(6,2)->(7,2)->(7,3)->(7,4)->(7,5)->(7,6)->(7,7)->(7,8)->(8,8)
//		最短路线为:(0,0)->(0,1)->(1,1)->(2,1)->(3,1)->(4,1)->(5,1)->(5,2)->(6,2)->(7,2)->(7,3)->(7,4)->(7,5)->(7,6)->(7,7)->(7,8)->(8,8)
//		最短路线长度为:17
	}
}

The dfs algorithm can be applied to other scenarios besides maze-type questions. For example, the following question uses the dfs algorithm to find the complete arrangement.

Exercise 3: DFS_Total permutation

Assuming that a positive integer n is given, find all the three-digit permutations and combinations and the number of cases that can be combined into a total of n numbers (1, 2...n) from 1 to n. (Numbers can be reused)
Input description: Input a positive integer n
Output description: Output the numbers that can be arranged and combined from small to large, wrap each number, and finally output the total number

Example 1:
Input:
1
Output:
111
1

Example 2:
Input:
3
Output:
111
112
113
121
122
123
......
333
27

/** 

*/

import java.util.*;
public class DFS_求全排列 {
    
    
	
	static int[] a=new int[3];
	static int count=0;
	//参数index指第几次从数组中取数
	public static void dfs(int index,int n) {
    
    
		
		if(index==3) {
    
    
			count++;
			for(int i=0;i<3;i++) {
    
    
				System.out.print(a[i]+" ");
			}
			System.out.println();
			
			return ;  
		}
		
		for(int i=1;i<=n;i++) {
    
    
				a[index]=i;
				dfs(index+1,n);
			}
			
		}

	public static void main(String[] args) {
    
    
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		dfs(0,n);
		System.out.println(count);
		sc.close();
	}
}

If some restrictions are given to the output numbers in the question, such as numbers that are divisible by 3, prime numbers, or if the "three-digit number" formed by the arrangement is changed to "four-digit number", etc., only need A little modification on this code should do the trick.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325899375&siteId=291194637