DFS 的基本思想是从起始节点开始,沿着一条路径尽可能深地访问,直到到达最深处,然后回溯到前一个节点,再尝试探索其他路径。这个过程会递归进行,直到所有的节点都被访问过。
在DFS中,每个节点都有三种状态:未访问、已访问但未探索完所有相邻节点、已访问且已探索完所有相邻节点。算法会确保每个节点都会被访问,并且在需要时进行回溯。
DFS常用于解决图相关的问题,如寻找路径、检测连通性、拓扑排序等。它也可以应用在树结构上,因为树可以看作是一种特殊的图。
具体步骤包括:
具体来说,这些变量在N皇后问题的解法中有以下用途:
- 选择一个起始节点。
- 访问该节点并标记为已访问。
- 对于当前节点的每个未访问的相邻节点,重复以上步骤。
- 当无法继续深入时,回溯到前一个节点,重复步骤3,直到所有节点都被访问过。
- 例题 N皇后问题
-
题目描述
在 N×N 的方格棋盘放置了 N 个皇后,使得它们不相互攻击(即任意 22 个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成 4545 角的斜线上。你的任务是,对于给定的 N,求出有多少种合法的放置方法。
输入描述
输入中有一个正整数 N≤10,表示棋盘和皇后的数量
输出描述
为一个正整数,表示对应输入行的皇后的不同放置数量。
输入输出样例
示例 1
输入
#include<bits/stdc++.h> using namespace std; int a[11][11]; int ans = 0; int n; bool check(int deep,int m){ for(int k = 0; k < n ; ++ k){ if(a[k][m]) return false; } // 检查所有方向以判断皇后是否会攻击 //下方还没有放置皇后,所以不用检查 for(int i = 1; i <= deep; i++) { if(a[deep - i][m]) return false; // 检查上方 if(m - i >= 0 && a[deep - i][m - i]) return false; // 检查左上方 if(m + i < n && a[deep - i][m + i]) return false; // 检查右上方 } return true; } void dfs(int deep){ if(deep == n){ ans++; return; } for(int i = 0; i < n ; ++ i){ if(check(deep,i)){ a[deep][i] = 1; // 放置皇后 dfs(deep+1); a[deep][i] = 0; // 移除皇后 } } } int main(){ cin>>n; dfs(0); cout<<ans; return 0; }
代码解析:
-
deep
:deep
表示当前递归深度,即当前处理的行数。- 在
dfs
函数中,通过递归的方式,每次处理一行,deep
表示当前处理的是第几行。
-
m
:m
表示当前处理的列数。- 在
dfs
函数中,通过循环遍历当前行的每一列,m
表示当前处理的是第几列。
deep
用于表示递归的深度,即处理的是棋盘的第几行。m
用于表示当前处理的列,通过循环遍历每一列。k
用于表示当前检查的行,通过循环遍历每一行,检查是否有其他皇后存在。-
k
:k
表示循环变量,用于遍历棋盘的行。- 在
check
函数中,通过循环遍历所有行,k
表示当前遍历的行。
a[11][11]
:表示一个11×11的二维数组,用于表示棋盘,其中的元素a[i][j]
表示第i
行第j
列的格子,1表示放置了皇后,0表示没有放置皇后。ans
:记录找到的合法解的数量。n
:表示N皇后问题中棋盘的大小,即N。- bool check(int deep,int m){
- 该函数用于检查在第
deep
行第m
列放置皇后是否合法。 - 首先检查同一列是否有其他皇后,然后检查所有方向以确保没有其他皇后攻击。
int deep
:表示当前处理的行数。int m
:表示当前处理的列数。-
for(int k = 0; k < n ; ++ k)
:这是一个循环,遍历所有的行k
(从0到n-1
)。int k
是循环变量,代表当前遍历的行。k < n
是循环的终止条件,确保遍历所有行。++k
是每次循环迭代后,将k
的值递增1。
-
if(a[k][m]) return false;
:在循环体内,检查当前列m
上的第k
行是否已经存在其他皇后(a[k][m]
是否为1)。- 如果
a[k][m]
为1,表示当前列上的某一行已经有皇后,说明不能在当前位置放置皇后。 - 因此,函数返回
false
,表示不合法。
- 如果
-
如果循环结束后没有触发
return false;
,则说明在当前列m
上没有其他皇后,可以在该列放置皇后,函数返回true
,表示合法。 -
a[deep - i][m]
:表示在当前行deep
上方第i
行、第m
列的位置是否已经放置了皇后。deep - i
表示在当前行deep
的上方第i
行。m
表示当前列。
-
if(a[deep - i][m])
:通过判断a[deep - i][m]
是否为1,即在上方是否存在其他皇后。
-
-
return false;
:如果上方已经存在其他皇后,则返回false
,表示当前位置(deep, m)
不合法,不能放置皇后。 -
deep == n
:判断当前递归的深度是否等于棋盘的大小。 - 如果等于,说明已经成功放置了
n
个皇后,即找到了一个符合条件的布局。 - 进入条件成立的分支。
-
check(deep, i)
:调用check
函数,检查在当前行deep
、列i
的位置是否可以放置皇后。- 如果返回
true
,表示可以放置皇后;如果返回false
,表示不能放置皇后。
- 如果返回
-
a[deep][i] = 1;
:如果当前位置可以放置皇后,则将二维数组a
中的相应位置置为1,表示在当前行deep
、列i
放置了皇后。 -
这是N皇后问题解法的核心思想,通过递归深度优先搜索,逐行放置皇后。dfs(deep+1);
:递归调用dfs
函数,处理下一行(深度+1)。 -
a[deep][i] = 0;
:在递归返回后,表示在当前行deep
、列i
的位置已经处理完毕,需要进行回溯操作,将之前放置的皇后移除,以尝试其他的列。- 将二维数组
a
中的相应位置置为0,表示移除了在当前行deep
、列i
的皇后。 -
这个检查是为了确保在当前位置
(deep, m)
的上方没有其他皇后,因为在N皇后问题中,皇后不能互相攻击,所以要检查同一列和同一斜线上是否已经存在其他皇后。这一部分是用于检查同一列的,而在之前的检查函数中,也包含了对斜线的检查。这个过程会不断地递归调用,深度优先搜索所有可能的布局,通过回溯操作,尝试不同的列,直到找到所有合法的N皇后布局。整个算法的核心在于递归搜索和回溯,确保不漏掉任何可能的解。
- 将二维数组