DFS (深さ優先探索) と BFS (幅優先探索)

目次

DFS (深さ優先検索)

完全順列の DFS ソリューション

 DFS を使用して再帰的に構築されたバイナリ文字列と再帰ツリーの構造解析

DFS -- プルーニング

DFS の例 -- 整数除算

 BFS (幅優先検索)

 全順列 BFS ソリューション


DFS (深さ優先検索)

        深さ優先検索 (DFS) は、最も一般的なグラフ検索方法の 1 つです。深さ優先検索は常にパスに沿って検索し、検索できない場合は直前にアクセスしたノードにフォールバックします。ディープ サーチとプライオリティ サーチの本質は、考えられるすべての状況を横断する継続的なサーチです。DFS 検索のプロセスは、パスがダウンするたびにツリー形式になります。

完全順列の DFS ソリューション

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);           
        }
    }
}

剪定されていない場合は、すべての子葉が出力されます

 したがって、完全な配置が必要な場合は、枝刈り、つまり再帰ループを判断する必要があります。

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。
        }
    }
}

このようにして得られた結果は、完全な配置の結果です。


 

 

 DFS を使用して再帰的に構築されたバイナリ文字列と再帰ツリーの構造解析

可能なすべてのバイナリ文字列 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;
    }
}

コードの実行過程、DFSの再帰過程と分岐・拡散の様子が見られる

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

プロセスは終了コード 0 で終了しました


DFS -- プルーニング

剪定とは、DFS における判断手法の 1 つで、答えを出さない枝や不要な枝を切り落とすことです。剪定のポイントは、どの枝をどこで切るかです。

整数 n を k 個の部分に分割します。各部分を空にすることはできません。2 つの分割スキームを同じにすることはできません (順序に関係なく)。

例: n = 7、k = 3、次の 3 つの除算方式は同じと見なされます。

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为下次可用的最小值
        }
    }
}

 操作結果:


DFS の例 -- 整数除算

整数は、整数の合計を超えないいくつかの形式に分割できます。次に例を示します。

4

4=1+1+1+1

4=1+1+2

4=1+3

4=2+2

4=4

合計5つの分割形態があり、合意されています

1) これらの加数は、小さいものから大きいものへの原則に従わなければなりません

2) 割り算として 4=1+3 と 4=3+1

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 + "+");
            }
        }
    }
}

答えを得ました:

 BFS (幅優先検索)

        幅優先探索 (BFS) は、最初のノードから開始し、生成ルールと制御戦略を適用してノードの最初の層を生成し、生成されたノードの中にターゲット ノードが含まれているかどうかを確認します。そうでない場合は、プロダクション ルールを使用してすべての第 1 レベル ノードを 1 つずつ展開して第 2 レベル ノードを取得し、第 2 レベル ノードにターゲット ノードが含まれているかどうかを 1 つずつ確認します。そうでない場合は、プロダクション ルールを使用してノードの 2 番目のレイヤーを展開します。このように、目的のノードが見つかるまで展開と確認を順番に行います。すべてのノードを展開してもターゲット ノードが見つからない場合、問題の解決策はありません。

 全順列 BFS ソリューション

        BFS は完全な配置のためにキューを使用する必要があります. まず、3 つのルート ノード 1 2 3 をキューに入れ、そのたびにキュー ヘッドをポップアップし、キュー ヘッドに対応する 2 つの子葉をキューに入れます。

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入队列
            }
        }
    }
}

 

おすすめ

転載: blog.csdn.net/weixin_71646897/article/details/129729173