DFS深度优先搜索例题

文章目录

  • 前言
  • 一、全排列问题
  • 二、n皇后问题
  • 总结


前言

深度优先搜算算法,又称DFS(Depth First Search)。DFS算法是一种搜索算法,而搜索算法实质上是一种枚举,即借助计算机的高性能来有目的地枚举一个问题的部分情况或这个问题的所有情况,进而求出问题的解的一种方法。


一、全排列问题

DFS深度优先搜索例题_第1张图片
首先的思路是,先对第一个数遍历(1,2,3)
拿1举例:

第一个空位选择1,标记[1]被使用;
第二个空位选没有被标记过的数字2,并且对2标记;
第三个空位选择没有被标记的数字,只能选择3;
三个位置都被填满后,取消对3的标记;
取消对2的标记;
输出结果:1 2 3;
并且返回第二个空位;

第二个空位选择没有被标记的数字3,并且对3标记;
第三个空位选择没有被标记的数字,只能选择2;
三个位置都被填满后,取消对2的标记;
取消对3的标记;
输出结果:1 3 2;
并且返回第二个空位;
进行完以上操作后,取消对1的标记,并且返回第一个空位
以此类推……;
代码如下:

#include

using namespace std;

const int N = 10;

int n;
int p[N];
bool st[N];

void dfs(int step){
	if(step == n ){
	    for(int i = 0; i < n;i ++ ) cout << p[i] << " ";
	    cout << endl;
	    return ;
}
    for(int i = 1 ; i <= n ;i ++ ){
        if(!st[i]){
            p[step] = i ;
            st[i] = true ;
            dfs(step + 1) ;
            st[i] = false ;
        }
    }

}
int main (){
    cin >> n ;
    dfs(0);
    return 0;
}

bool st[N] :
标记被使用的数组st[N];被标记为:true;未被标记为:false;
step:
表示位置。2 3 1,就是step = 1的地方填2;就是step = 2的地方填3;就是step = 3的地方填1;
dfs(step + 1):
表示对下一个位置进行填数,一种递归思想;

二、n皇后问题

DFS深度优先搜索例题_第2张图片
DFS深度优先搜索例题_第3张图片
DFS深度优先搜索例题_第4张图片

这道题与例题一相比略有难度;
n皇后问题,就是考虑皇后放置的位置,对于每一行,需要枚举每个可以放置皇后的位置,我们需要判断当前位置(第i行)是否满足条件,即判断这个位置是否与放置好的前i-1行的皇后的位置相冲突,如果冲突,说明这个位置不合适;则跳到下一列(注意是列),若还是冲突,继续跳到下一列,直到最后一列,如果最后一列也不能放置,则说明此时放置方法出错,则回到上一个皇后向之前放置的下一列重新放置。 否则的话,就可以枚举下一行皇后的位置,直至第n行。
代码如下:

#include 
using namespace std;
const int N = 20; 

// bool数组用来判断搜索的下一个位置是否可行
// col列,dg对角线,udg反对角线
// g[N][N]用来存路径

int n;
char g[N][N];
bool col[N], dg[N], udg[N];

void dfs(int u) {
    // u == n 表示已经搜了n行,故输出这条路径
    if (u == n) {
        for (int i = 0; i < n; i ++ ) puts(g[i]);   // 等价于cout << g[i] << endl;
        puts("");  // 换行
        return;
    }

    // 枚举u这一行,搜索合法的列
    int x = u;
    for (int y = 0; y < n; y ++ )
        // 剪枝(对于不满足要求的点,不再继续往下搜索)  
        if (col[y] == false && dg[y - x + n] == false && udg[y + x] == false) {
            col[y] = dg[y - x + n] = udg[y + x] = true;
            g[x][y] = 'Q';
            dfs(x + 1);
            g[x][y] = '.';  // 恢复现场
            col[y] = dg[y - x + n] = udg[y + x] = false;
        }
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            g[i][j] = '.';

    dfs(0);

    return 0;
} 

总结

DFS总体上使用了栈的思想,即先进后出,因此在递归时需要“恢复现场”,另外,DFS和BFS在使用中的特点总结如下:
如果只是要找到某一个结果是否存在,那么DFS会更高效。因为DFS会首先把一种可能的情况尝试到底,才会回溯去尝试下一种情况,只要找到一种情况,就可以返回了。但是BFS必须所有可能的情况同时尝试,在找到一种满足条件的结果的同时,也尝试了很多不必要的路径;
如果是要找所有可能结果中最短的,那么BFS会更高效。因为DFS是一种一种的尝试,在把所有可能情况尝试完之前,无法确定哪个是最短,所以DFS必须把所有情况都找一遍,才能确定最终答案(DFS的优化就是剪枝,不剪枝很容易超时)。而BFS从一开始就是尝试所有情况,所以只要找到第一个达到的那个点,那就是最短的路径,可以直接返回了,其他情况都可以省略了,所以这种情况下,BFS更高效。

你可能感兴趣的:(ACM每周知识点,深度优先,算法,c++)