[Detailed explanation of dfs and bfs of Java algorithm]

I won't dove again next time (つಥ㉨ಥ)つI swear, really! ! !

1. dfs

Depth-first traversal(Depth First Search, DFS for short)
Depth first traverses each node, you need to usethe stack(Stack) This data structure. The characteristics of Stack arefirst in last out, first push the right node into the stack, and then push the left node into the stack, so that the stacking order is first the left node and then the right node.
DFSIt is a search algorithm in graph theory. It can start from a root node, traverse all child nodes, and then search all the collections that can form a tree in the graph to achieve the purpose of global search. So many problems can use dfs to traverse each situation to get the optimal solution, but because the time complexity is too high, we also call itbrute force search

A moving picture to understanddfs and bfsthe difference:
insert image description here
dfs sequence为:1—>2—>3—>2—>1—>4—>5—>6—>5—>4—>7—>4—>1—>8—>9—>8—>1

1.1 dfs recursion

recursionTwo conditions must be met, one iscall yourself,one iswith termination condition. These two conditions must be met at the same time, and one cannot be missing. and the termination condition must be in the recursivevery beginningHere is the basic template (。・ω・。)ノ♡

public class newText2 {
    
    
    public static void main(String[] args) {
    
    
        dfs( step );
    }
    static void dfs(int step) {
    
    
       
        if (暴搜结束的条件)  //
        {
    
    
            System.out.println(输出题目答案);
            return ; //结束
        }
        
        if (x >= n) return;  //判断边界
        
        for ( i=1; i<=n; i++) //尝试每一种可能
        {
    
     
		     dfs(step+1) //继续下一步
		}
    }
}

Now that you know about dfs, let’s do it ( ૢ⁼̴̤̆ ㉨ ⁼̴̤̆ ૢ)♡

There is no difference between chess pieces placed on a chessboard of a given shape (the shape may be irregular). It is required that any two chess pieces cannot be placed in the same row or column of the chessboard when placing them. Please program to find the total number of all feasible arrangements for placing k pieces on a chessboard of a given shape and size.
Input
4 4
…#
…#.
.#…
#…
Sample Output
1

Idea:
Chess pieces can only be placed on # and k pieces must be in different rows and different columns, so the state is restricted here. If we use BFS to do it, it will definitely not be easy to do, but we can just use DFSBacktrackThe feature is to do this topic;
define an array VIS [i], which marks whether there is a chess piece in the i-th column. If there is a chess piece in the i-th column, then we make vis [i] == true.

import java.util.*;
import java.util.Scanner;
public class newText2 {
    
    
    public static void main(String[] args) {
    
    
        Text draw = new Text();
        Scanner mc = new Scanner(System.in);
        int n = mc.nextInt();//总行数
        int k = mc.nextInt();//要放几个棋子
        char[][] mp = new char[n][];  //棋盘
        String t = mc.nextLine();
        for (int j = 0; j < n; j++) {
    
      //输入棋盘
            String s = mc.nextLine();
            mp[j] = s.toCharArray();
        }
        draw.dfs(0, 0, mp, n, k);
        System.out.println(draw.cnt);
    }

    static class Text {
    
    
       
       int cnt = 0;
       
        void dfs(int x, int way, char[][] mp, int n, int k) {
    
    //用way记录我们放了多少棋子
        boolean[] vis = new boolean[n];//标记每一列
            if (way == k) {
    
    
                cnt++;//cnt记录方案数
                return;//一定记得要return
            }
            if (x >= n) return;//这是判界,一共有n行不能多出去
            for (int i = 0; i <  mp[x].length; i++) {
    
    //判断这一行的每一列
                if (mp[x][i] == '#' && !vis[i]) {
    
    //如果说这mp[x][i]刚好是# 而且第i列是 false没有放棋子
                    vis[i] = true;//我们就放上,并作标记
                    dfs(x + 1, way + 1, mp, n, k);//在下一行放,这一行已经无法放了,不同行不同列
                    vis[i] = false;//此处为回溯的关键点,有疑问的话,请看下图分解
                }
            }
            dfs(x + 1, way, mp, n, k);//这一行找不到的话就直接进行下一行
        }
    }
}

At this point, friends may have some doubts. Let's take a 2*3 chessboard and place 2 chess pieces as an example.

# 0 #
0 0 0

dfs(x + 1, way + 1);//put in the next line, this line can no longer be placed,step one
vis[i] = false;//Here is the key point of backtracking,step two

When dfs executes step 1, because it calls itself, it will continue to "matry dolls" until it is out of bounds and triggers return, and then step 2 will be executed, as shown in the figure below:

# 1 #
1 # 0

When the second number is obtained, the for loop i=0, and then execute step 2 vis[i] = false to cancel the mark; the for loop continues with i=1, i=2. Until a vacancy is found, otherwise go to the next line (out of bounds trigger return)
when the first number has been traversed, at this time the first number i=1, the for loop continues to traverse i=2,
because vis[i] = False cancels the mark, so that the i=2 traversal proceeds normally.

recursivebenefit: The code is more concise and clear, and the readability is better.
In fact, the recursive code is clearer. Generally speaking, a person can easily write a recursive algorithm for traversing a binary tree in front, middle, and back order. It is more challenging to write the corresponding non-recursive algorithm. So the recursive code is more concise and clear.

recursionharm: Since recursion requires the system stack, sospace consumptionMuch larger than non-recursive code. Moreover, if the recursion depth is too large, exceeding the maximum depth of recursion, the system may not be able to sustain

2. bfs

breadth first traversal(Breath First Search referred to as BFS), refers to starting from an untraversed node in the graph, first traversing the adjacent nodes of this node, and then traversing the adjacent nodes of each adjacent node in turn.

The breadth-first traversal animation of the above-mentioned tree is as follows, and the value of each node is their traversal order. Therefore, breadth-first traversal is also called layer-order traversal, first traversing the first layer (node ​​1), then traversing the second layer (node ​​2, 3, 4), the third layer (5, 6, 7, 8), and the fourth layer (9, 10).
insert image description here
Depth-first traversal uses the stack, while breadth-first traversal needs to usequeue(Queue) to store node objects, the characteristics of the queue arefirst in first out. First insert the left node into the queue, and then insert the right node. When the queue is dequeued, the left node is first out, and then the right node is out.
Queue to achieve breadth-first traversal, the animation is as follows:
insert image description here
Breadth-first search can be answeredtwo typesquestion.
❑ The first type of question: Starting from node A, is there a path to node B? (Whether there is a path problem)
❑ The second type of problem: Starting from node A, which path is the shortest to node B? (shortest path problem)

1. There are two common problems in bfs

1.1whetherthere is a path problem

Water problem:

There are two jugs with capacities jug1Capacity and jug2Capacity liters. The supply of water is unlimited. SurewhetherIt is possible to get exactly targetCapacity in liters using both jugs.
If targetCapacity liters of water are available, use one or two of the above jugs at the end to hold the targetCapacity liters obtained.
You can:
Fill any jug
Empty any jug
Pour from one jug to the other until full or empty

Example 1:
Input: jug1Capacity = 3, jug2Capacity = 5, targetCapacity = 4
Output: true
.
Example 2:
Input: jug1Capacity = 2, jug2Capacity = 6, targetCapacity = 5
Output: false
.
Example 3:
Input: jug1Capacity = 1, jug2Capacity = 2, targetCapacity = 3
Output: true
.
Prompt:
1 <= jug1Capacity, jug2Capacity, targetCapacity <= 106

Idea:
Notice that when operating the kettle for this question, it is impossible for the two kettles to be half full at the same time. If one jug is half full, the other must be either full or empty. And if a kettle is half full (the other one is empty or full at this time), you can't fill the kettle directly, and you can't pour out the half-full water, because it will return to the initial state, There's no point in doing that.
Allowed:
Fill any jug
Empty any jug
Pour water from one jug to another until it is full or empty
Six operations:
// fill pot X
// fill pot Y
// fill X jug empty
// empty jug Y
// pour water from jug X into jug Y until full or empty
// pour water from jug Y into jug X until full or empty.

import java.lang.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class newText2 {
    
    
    public static void main(String[] args) {
    
    
        Scanner mc=new Scanner(System.in);
        int x = mc.nextInt(); //分别输入两个瓶子的容积
        int y = mc.nextInt();
        int z = mc.nextInt();
        Solution sou =new Solution();
        System.out.println(sou.canMeasureWater(x,y,z));

    }
    static class Solution {
    
    
        public boolean canMeasureWater(int x, int y, int z) {
    
    

            Queue<int[]> Queue = new LinkedList<int[]>(); //广度优先遍历使用队列
            Queue.add(new int[]{
    
    0, 0}); //添加
            Set<Long> seen = new HashSet<Long>(); //long 用于保存长类型数据
            while (!Queue.isEmpty()) {
    
    
                if (seen.contains(hash(Queue.peek()))) {
    
      //哈希查重
                    Queue.poll();  //删除队头元素
                    continue;
                }
                seen.add(hash(Queue.peek())); //无重复则 添加

                int[] state = Queue.poll(); //删除并返回队头被删除的那个元素
                int remain_x = state[0];    //获取新状态
                int remain_y = state[1];
                if (remain_x == z || remain_y == z || remain_x + remain_y == z) {
    
    
                    return true;
                }

                Queue.add(new int[]{
    
    x, remain_y}); // 把 X 壶灌满
                Queue.add(new int[]{
    
    remain_x, y}); // 把 Y 壶灌满
                Queue.add(new int[]{
    
    0, remain_y}); // 把 X 壶倒空
                Queue.add(new int[]{
    
    remain_x, 0}); // 把 Y 壶倒空

                Queue.add(new int[]{
    
    remain_x - Math.min(remain_x, y - remain_y), remain_y + Math.min(remain_x, y - remain_y)});
                // 把 X 壶的水灌进 Y 壶,直至灌满或倒空
                Queue.add(new int[]{
    
    remain_x + Math.min(remain_y, x - remain_x), remain_y - Math.min(remain_y, x - remain_x)});
            }  // 把 Y 壶的水灌进 X 壶,直至灌满或倒空。
            return false;
        }

        public long hash(int[] state) {
    
    return  state[0] * 1000001L + state[1];
        }
    }
}

In fact, the problem of pouring water is usedmathmethod is faster.

import java.util.Scanner;
public class newText2 {
    
    
    public static void main(String[] args) {
    
    
        Scanner mc = new Scanner(System.in);
        int x = mc.nextInt(); //分别输入两个瓶子的容积
        int y = mc.nextInt();
        int z = mc.nextInt();
        Solution sou = new Solution();
        System.out.println(sou.canMeasureWater(x, y, z));

    }

    static class Solution {
    
    
        public boolean canMeasureWater(int x, int y, int z) {
    
    
            if (z == 0) return true;
            if (z > (x + y)) return false;
            int a = Math.min(x, y);
            int b = Math.max(x, y);

            boolean[] record = new boolean[b];

            int remain = 0;
            while (!record[remain]) {
    
    
                record[remain] = true; //标记状态
                remain = (remain + a) % b;
                if (remain == z || remain + b == z) return true;
            }
            return false;
        }
    }
}

1.2 Shortest path problem

2.1 Maze problem:

Returns the number of steps in the shortest path

In the N*M maze, calculate and output the shortest path from S to G
'#', '.', 'S', 'G' respectively represent walls, passages, starting points, and ending points
insert image description here

Problem-solving idea: type n, m, and maze; record the positions of S and G; DBS wide search, create two one-dimensional arrays to record the starting and ending positions, and use d[][] to mark the path traveled; please refer to the specific operation code.

java.lang.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class newText2 {
    
    
    public static void main(String[] args) {
    
    
 Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//行数
        int m = sc.nextInt();//列数
        String t = sc.nextLine();
        char[][] map = new char[n][m];
        int[] begin = new int[2]; //起点位置
        int[] end = new int[2];  //终点位置

        for (int i = 0; i < n; i++) {
    
     //按行输入字符,共输入n行,每输入一行,就依次判断是否 起点或终点
            String s = sc.nextLine();
            map[i] = s.toCharArray();
            if (s.contains("S")) {
    
      // 当字符串 s 包含 " " 内指定的 char值时,方法返回true
                begin[0] = i;  //记录起点“s"所在行数,  下一行代码记录起点“s"所在列数
                begin[1] = s.indexOf("S");//查找指定字符"s"在其字符串中的下标。若"s"存在则返回所在字符串下标;不在则返回-1.
            }
            if (s.contains("G")) {
    
    
                end[0] = i;   //记录终点”G“所在 行数列数
                end[1] = s.indexOf("G");
            }
        }
        Solution put=new Solution();
        System.out.println( put.bfs(map, begin, end));
    }

    public static class Solution {
    
    
        public int bfs(char[][] map, int[] begin, int[] end) {
    
    
            int[] dx = {
    
    1, 0, -1, 0};//移动的四个方向
            int[] dy = {
    
    0, 1, 0, -1};
            int[][] d = new int[map.length][map[0].length];// 记录 到终点最短路径数的二维数组

            Queue<int[]> que = new LinkedList<int[]>();  //储存将要进行处理的点
            for (int i = 0; i < d.length; i++) {
    
      //将所有的位置都初始化为最大
                for (int j = 0; j < d[0].length; j++) {
    
    
                    d[i][j] = Integer.MAX_VALUE; //Integer.MAX_VALUE 是整型可以支持的最大数
                }
            }
            que.offer(begin);//将起始点放入队列
            d[begin[0]][begin[1]] = 0;//将起始点最短路径设为0
            while (!que.isEmpty()) {
    
    // 队列非空时,执行循环
                int[] current = que.poll(); //取出队列中最前端的点
                if (current[0] == end[0] && current[1] == end[1])  break;//如果是终点则结束,最短路径为0
                for (int i = 0; i < 4; i++) {
    
    //四个方向循环

                    int ny = current[0] + dy[i];
                    int nx = current[1] + dx[i];
                    //判断是否可以走
                    if (ny >= 0 && ny < d.length && nx >= 0 && nx < d[0].length && map[ny][nx] != '#' && d[ny][nx] == Integer.MAX_VALUE) {
    
    

                        d[ny][nx] = d[current[0]][current[1]] + 1;//如果可以走,则将该点的距离加1
                        int[] c = {
    
    ny, nx};//将该点放入队列等待下次处理
                        que.offer(c);
                    }
                }
            }
            return d[end[0]][end[1]];
        }
    }
}


.

2.2reductionpath

Returns the number of steps and the path of the shortest path

It represents a maze, where 1 represents the wall and 0 represents the path that can be walked. It can only walk horizontally or vertically, but not diagonally. It requires programming to find the shortest route from the upper left corner to the lower right corner.
Input
a two-dimensional array of n × m, representing a maze. The data is guaranteed to have a unique solution.
Output
The shortest path from the upper left corner to the lower right corner, in the format shown in the sample.
Sample Input
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output
8
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

Problem-solving idea:
bfs+ path restoration, create a boolean-like two-dimensional array visit[][] to mark the path, and enter the queue from the starting point to the end point through breadth-first search. When searching, search in lexicographical order, and encapsulate the path of each step intoCoordinate classSave in, when the end point is searched, the saved path will be output directly.

import java.lang.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class newText1 {
    
    
    public static void main(String[] args) {
    
    
        for (int i = 0; i < n; i++) {
    
     //输入迷宫
            String s = sc.next();
            for (int j = 0; j < m; j++) {
    
    
                map[i][j] = s.charAt(j) - '0'; //string类型转换为int类型的二维数组
            }
        }
        bfs(new Point(0, 0), n, m);
    }

    public static int dir[][] = new int[][]{
    
    {
    
    1, 0}, {
    
    0, -1}, {
    
    0, 1}, {
    
    -1, 0}}; //四个移动方向  对应下 左 右 上
    static Scanner sc = new Scanner(System.in);
    static int n = sc.nextInt(); //行数
    static int m = sc.nextInt(); //列数
    public static int[][] map = new int[n][m]; //储存迷宫
    public static boolean[][] visit = new boolean[n][m]; //标记走过路径,默认值为false

    public static void bfs(Point start, int n, int m) {
    
    
        Queue<Point> q = new LinkedList<Point>();
        q.add(start);
        visit[start.i][start.j] = true; // 标记起点
        while (!q.isEmpty()) {
    
    
            Point p = q.peek(); // 返回队列的头元素

            if (p.i == n - 1 && p.j == m - 1) {
    
     // 移动至终点时输出
                System.out.println(p.step);
                System.out.println(p.record);
                return;
            }

            for (int i = 0; i < 4; i++) {
    
        //四个方向按'D', 'L', 'R', 'U'即对应 下 左 右 上 ,尝试移动
                int new_i = p.i + dir[i][0];
                int new_j = p.j + dir[i][1];
                Point temp = new Point(new_i, new_j);

                if (new_i >= 0 && new_j >= 0 && new_i < n && new_j < m && !visit[new_i][new_j] && map[new_i][new_j] != 1) {
    
    
                    visit[new_i][new_j] = true;
                    String y = String.valueOf(new_i); //将基本数据型(int)转换成字符串
                    String x = String.valueOf(new_j);
                    temp.step = p.step + 1;
                    temp.record = p.record + "(" + y + "," + x + ")" + "\n";
                    q.add(temp); //封装入坐标类
                }
            }
            q.poll(); //获取并删除队列中的第一个元素,获取新的new_i, new_j继续判断
        }
    }
}

class Point {
    
    
    int i;
    int j;
    int step; //走过步数
    String record; //路径

    public Point(int i, int j) {
    
    
        this.i = i;
        this.j = j;
        step = 0;
        record = "";
    }
}

Guess you like

Origin blog.csdn.net/qjjspl_/article/details/123957513