目次
DFS を使用して再帰的に構築されたバイナリ文字列と再帰ツリーの構造解析
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入队列
}
}
}
}