シンプルで理解しやすいDFS(2)抽象DFS

迷路などのトピックで使用されるdfsアルゴリズムは、検索プロセスを想像しやすく、一部の問題は検索プロセスを想像するのがそれほど簡単ではありません。このタイプの問題をdfsの抽象的な形式と呼びます。

例1:n個の整数が与えられた場合、選択されたK個の数値の合計が合計になるようにK個の数値を選択する必要があります。

このような問題の場合、検索するための明確なマップはありませんが、dfsを使用してこの問題を解決することはできます。

  1. 番号ごとに、選択を列挙するかどうかの2つのケースがあります。
  2. 検索プロセスでは、Sを使用して現在選択されている値の総数を記録し、kを使用して選択された数値の数を記録し、deepは現在列挙されている数値が選択されているかどうかを示します。
  3. dfsの最初のレイヤーでは、最初の番号を選択するかどうかを列挙できます。最初の番号を選択した場合は、最初の番号にSを追加し、k + 1を追加すると、dfsは次のレイヤーに入ります。それ以外の場合、dfsは直接次のレベルに入ります。
  4. 2番目のレイヤーで、2番目の値に対して同じプロセスを実行します。dfsプロセス中に、選択された数値の数が記録されます。k個の数値が選択されている場合は、S値が合計に等しいかどうかを判別します。レイヤーごとに、選択するか選択しないかの2つの選択肢があります。選択肢が異なると、検索は別のブランチに入り、検索を続行します

上記のdfsのアイデアの助けを借りて、次のコードを書くことができます。

#include <iostream>
using namespace std;
int a[40];
int n, k, sum, ans;
//i表示选择第i个数,cnt记录选择的个数,s表示选取数的和
void dfs(int i, int cnt, int s) {
	if (i == n) {
		if (cnt == k && s == sum) {
			ans++;
		}
		return;
	}
	dfs(i + 1, cnt, s); //不选该数
	dfs(i + 1, cnt + 1, s + a[i]); //选择该数
}
int main() {
	cin >> n >> k >> sum;
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
	}
	ans = 0;
	dfs(0, 0, 0);
	cout << ans << endl;
	return 0;
}

入力:

5 3 9
1 2 3 4 5

出力:

2

例2:Nクイーンの問題

Nクイーンの問題は古典的な問題です。NクイーンをN ∗ Nチェス盤に配置し、各行の後に1つずつ配置して、お互いが攻撃しないようにします(同じ行、同じ列、同じ対角線のクイーンは自動的に配置されます)攻撃)
ここに画像の説明を挿入
上の写真は、8人の女王の合法的な解決策です。Nクイーンの問題とは、Nクイーンを合計で配置する方法がいくつあるかを指します。

この質問は、dfsのアイデアを使用することもできます。つまり、最初に最初の行で埋められる位置を決定し、次に最初の行の位置に従って埋めることができないボード上の位置をマークします(同じではありません)行、同じ列、同じ対角線)次の行を塗りつぶし、各行にクイーンが表示されるまで、毎回前の状態の塗りつぶし位置に従って次の行を塗りつぶします。

埋めることができないボード上の位置をマークするには、次のより巧妙な方法を使用できます。

//col标记列,x1标记正斜线,x2标记反斜线
int col[10], x1[20], x2[20];
col[i] = x1[r + i] = x2[r - i + n] = true;  
//r表示填充第r行,(r, i)表示放置的位置,r + i 表示正斜线,r - i + n表示反斜线
//可以简单的推理一下,每一条正斜线的r + i都相等,反斜线的r - i都相等,为了
//防止负数,加一个n确保其为正数

次に、上記のアイデアに従って、次のコードを記述できます。

#include <iostream>
using namespace std;
int n;
int ans;
bool col[10], x1[20], x2[20];
bool check(int r, int i) {
	return !col[i] && !x1[r + i] && !x2[r - i + n];
}
void dfs(int r) {
	if (r == n) {
		ans++;
		return;
	}
	for (int i = 0; i < n; ++i) {
		if (check(r ,i)) {
			col[i] = x1[r + i] = x2[r - i + n] = true;
			dfs(r + 1);
			col[i] = x1[r + i] = x2[r - i + n] = false;
		}
	}
}
int main() {
	scanf("%d", &n);
	dfs(0);
	cout << ans << endl;
	return 0;
}

入力:

4

出力:

2

input1

8

output2:

92

dfsの問題解決を抽象的な形で理解することは、dfsの理解を深めるのに役立ちます
.nクイーン問題の解決を理解すると、2nクイーン問題の解決を試みることができます:このアイデアを検討し、解決するためにnクイーン問題に分解してから合格しますdfsのパラメーターpを入力し、渡されたパラメーターpの値に従って黒の女王と白の女王のどちらを配置するかを決定します(このアイデアは参照用です)

おすすめ

転載: blog.csdn.net/weixin_45024585/article/details/107686635