DFS (Depth First Search) and BFS (Breadth First Search)

Table of contents

DFS (Depth First Search)

DFS solution for full permutation

 Structural Analysis of Binary Strings and Recursive Trees Recursively Built Using DFS

DFS--pruning

DFS Example--Integer Division

 BFS (Breadth First Search)

 Full permutation BFS solution


DFS (Depth First Search)

        Depth First Search (DFS) is one of the most common graph search methods. Depth-first search will always search along a path, and fall back to the node just visited when it cannot be searched. The essence of deep search and priority search is continuous search, traversing all possible situations. The process of DFS search is in the form of a tree, each time a path goes down.

DFS solution for full permutation

public class DFS {
    public static void main(String[] args) {
        DFS(0, "", 3);
    }

    public static void DFS(int depth, String ans, int n) {
        if (depth == n) {//深度等于n时就输出
            System.out.print(ans + " ");
            return;
        }
        for (int i = 1; i <= n; i++) {
                DFS(depth + 1, ans + i, n);           
        }
    }
}

If it is not pruned, all cotyledons will be output

 Therefore, in the case where full arrangement is required, we need to perform pruning, that is, to judge the recursive loop

public class DFS {
    public static void main(String[] args) {
        DFS(0, "", 3);
    }

    public static void DFS(int depth, String ans, int n) {
        if (depth == n) {//深度等于n时就输出
            System.out.print(ans + " ");
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (! ans.contains("" + i)) {
                //目前已经生成的ans串用过的不能再用(剪枝)
                DFS(depth + 1, ans + i, n);
            }
            //public boolean contains(CharSequence s)
            // 当且仅当此字符串包含指定的 char 值序列时,返回 true。
        }
    }
}

The result obtained in this way is the result of the full arrangement.


 

 

 Structural Analysis of Binary Strings and Recursive Trees Recursively Built Using DFS

All possible binary strings 0000 -> 1111

public class binaryStringRecurrence {

    public static void main(String[] args) {
        DFS(0, "");//从0层开始
    }

    public static void DFS(int depth, String binary) {//depth为深度,binary为求出的二进制串
        System.out.printf("%sdg(%d, %s)\n", Lpad(depth), depth, binary);//用来查看各个节点
        if (depth == 4) {//深度为4的时候输出字符串
            System.out.println(binary);
            return;
        }
        //每次开枝散叶都需要开2支,左边补0,右边补1
        DFS(depth + 1, binary + "0");
        DFS(depth + 1, binary + "1");

    }

    public static String Lpad(int n) {//用来打印空格
        String ans = "";
        for (int i = 1; i <= n; i++) {
            ans += "        ";
        }
        return ans;
    }
}

Code execution process, you can see the recursive process of DFS and the way of branching and spreading

dg(0, )
        dg(1, 0)
                dg(2, 00)
                        dg(3, 000)
                                dg(4, 0000)
0000
                                dg(4, 0001)
0001
                        dg(3, 001)
                                dg(4, 0010)
0010
                                dg(4, 0011)
0011
                dg(2, 01)
                        dg(3, 010)
                                dg(4, 0100)
0100
                                dg(4, 0101)
0101
                        dg(3, 011)
                                dg(4, 0110)
0110
                                dg(4, 0111)
0111
        dg(1, 1)
                dg(2, 10)
                        dg(3, 100)
                                dg(4, 1000)
1000
                                dg(4, 1001)
1001
                        dg(3, 101)
                                dg(4, 1010)
1010
                                dg(4, 1011)
1011
                dg(2, 11)
                        dg(3, 110)
                                dg(4, 1100)
1100
                                dg(4, 1101)
1101
                        dg(3, 111)
                                dg(4, 1110)
1110
                                dg(4, 1111)
1111

Process ended with exit code 0


DFS--pruning

Pruning is a judgment technique in DFS, which is to cut off branches that do not produce answers or are unnecessary. The key to pruning is which branch to cut and where to cut.

Divide the integer n into k parts, each part cannot be empty, and any two partitioning schemes cannot be the same (regardless of the order)

For example: n = 7, k = 3, the following three division schemes are considered to be the same

115    151    511

import java.util.Scanner;

public class nDivideK {
    public static int ans;//记录成功方案的次数
    public static int cnt;//记录DFS调用的次数
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();//被划分数
            int k = scanner.nextInt();//规定划分份数
            DFS(n, k, 1, "");//i初始为1,因为第一次最小可用值就是1
            System.out.println("方案数为:" + ans);
            System.out.println("DFS调用的次数为:" + cnt);
        }
    }

    /**
     * 整数n划分k份的方案
     * @param n 被划分数
     * @param k 规定划分份数
     * @param min 保证构造非降序,如 1 1 5和 5 1 1是 等价的。表示目前被拆分使用的最大数,下次拆分可用的最小值
     * @param fangan 记录划分方案次数
     */
    public static void DFS(int n, int k, int min, String fangan) {
        cnt++;//只要DFS被调用cnt就自增
        if (k == 1 && min <= n) {//这里min需要小于等于n,要不无法继续拆解
            ans++;//找到正确的方案,ans就自增
            System.out.println(fangan + n);
            return;
        }
        if (min * k > n) return;//剪枝
        //开枝散叶
        for (int i = min; i <= n ; i++) {
            DFS(n - i, k - 1, i, fangan + i +"+");
            //n-i为拆分后的数,k-1为剩余的拆分次数,i为下次可用的最小值
        }
    }
}

 operation result:


DFS Example--Integer Division

An integer can be divided into several forms that do not exceed the sum of integers, for example:

4

4=1+1+1+1

4=1+1+2

4=1+3

4=2+2

4=4

There are a total of 5 division forms, agreed

1) These addends must follow the principle from small to large

2) 4=1+3 and 4=3+1 as a division

public class DFSIntSplit {
    public static void main(String[] args) {
        int n = 4;
        DFS(n, 0, 0, "");
    }

    /**
     *
     * @param n 被拆分的数
     * @param nowget 目前已经得到的值
     * @param maxused 记录目前拆分已经使用的最大值
     * @param ans 拆分方案
     */
    public static void DFS(int n, int nowget, int maxused, String ans) {
        if (nowget == n) {//当已经得到的值等于被拆分的数时就结束
            System.out.println(n + "=" + ans);
            return;
        }
        //开枝散叶
        for (int i = 1; i <= n - nowget ; i++) {//需要累加到n,已经累加到了nowget,所以要n - nowget
            if (i >= maxused && i == n - nowget) {
                //i必须大于当前拆分的最大值才可以继续递归
                //如果是最后一次循环(i==n-nowget),那么ans + i就不需要再加 "+" 了
                DFS(n, nowget + i, i, ans + i);
            } else if (i >= maxused) {
                DFS(n, nowget + i, i, ans + i + "+");
            }
        }
    }
}

got the answer:

 BFS (Breadth First Search)

        Breadth First Search (BFS) starts from the initial node, applies production rules and control strategies to generate the first layer of nodes, and checks whether the target node is among the generated nodes. If not, use the production rules to expand all the first-level nodes one by one to obtain the second-level nodes, and check whether the second-level nodes contain the target node one by one. If not, use the production rules to expand the second layer of nodes. In this way, expand and check in turn until the target node is found. If no target node is found after expanding all the nodes, the problem has no solution.

 Full permutation BFS solution

        BFS needs to use the queue for the full arrangement. First, put the three root nodes 1 2 3 into the queue, pop up a queue head each time, and enqueue the two cotyledons corresponding to the queue head.

import java.util.LinkedList;
import java.util.Queue;

public class BFS {
    public static void main(String[] args) {
        int n = 3;
        Queue<String> queue = new LinkedList<String>();
        for (int i = 1; i <= n; i++) {
            //将1 2 3入队列
            queue.offer("" + i);
        }
        while (!queue.isEmpty()) {//如果队列不为空就循环
            //public boolean isEmpty()
            // 当且仅当 length() 为 0 时返回 true。
            //返回:如果 length() 为 0,则返回 true;否则返回 false。
            String head = queue.poll();//弹出列头
            for (int i = 1; i <= n; i++) {
                if (head.contains("" + i)) continue;//如果head包含i,就不扩展了
                String son = head + i;//子叶等于列头+i
                if (son.length() == n) System.out.println(son);//长度为n说明就产生了三阶的全排列了,就输出
                else queue.offer(son);//否则就将son入队列
            }
        }
    }
}

 

Guess you like

Origin blog.csdn.net/weixin_71646897/article/details/129729173