0
点赞
收藏
分享

微信扫一扫

【C++】蓝桥杯必备算法—— DFS“暴搜” 排列数字+n皇后问题 ( 图解+详细注释 )AcWing 842. 排列数字 AcWing 843. n-皇后问题

目录

在这里插入图片描述


在这里插入图片描述

🌟一、了解DFS

✨1、DFS(Depth First Search)

✨2、回溯——DFS核心

回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择。下图为遍历路线,所以假设没找到,DFS就是这样子走的。从1开始, 1-2的那个回溯是指 5》4》2》1
在这里插入图片描述

✨3、重学递归——DFS本质

🌟二、AcWing 842. 排列数字

✨1、题目

题目链接传送门
在这里插入图片描述

✨2、思路

在这里插入图片描述
由此可以定义一个数组path[N] 来保存当前的路径/模拟DFS的过程,当这个数组数字填满的时候,就把当前的排列数字输出出来,然后回溯的时候就需要一个核心操作回溯(恢复现场),比如走到1 2 3 回溯 到结点的过程为 123 —>12—>1 ,这个过程的核心操作就是需要把原来的位置恢复到原有状况,然后递归。

✨3、AC代码

#include <iostream>
using namespace std;
const int N = 7;
int n;
int path[N]; //保存路径
bool st[N]; //用于记录该店是否来过  反正dfs重新进入

void dfs(int u) { //u表示层数
    if (u == n) { //当数填满n位数时  输出n位数 并且换行
        for (int i = 0; i < n; i ++) {  
            printf("%d ", path[i]);
        } 
        puts("");
        return ;
    }

    for (int i = 1; i <= n; i ++) { 
        if (!st[i]) { //如果这个位置空的话(没有来过)
            path[u] = i;
            st[i] = true; //填数的时候记录一下
            dfs(u + 1); //访问下一层
            st[i] = false; //回溯的时候 恢复现场[]
        }
    }
}

int main () {
    cin >> n;
    dfs(0); //这个题直接遍历
    return 0;
}

🌟三、AcWing 843. n-皇后问题

✨1.题目

题目链接
在这里插入图片描述

✨2、思路一

①、ac代码:

#include <iostream>
using namespace std;
const int N = 20;//对角线元素 2n-1 取20防止越界 
int n;
char g[N][N]; //存储图 
bool row[N],col[N], dg[N], udg[N]; //udg 副对角线 /
//英语单词 column 列   diagonal 主角线 \ 
//row 行

void dfs (int x,int y,int s) {  //xy为坐标 (x,y) s为 n皇后放置个数

    if (y == n) { //当x走到行末尾的时候  
        y = 0;    //转到下一行的第一个
        x++;
    }

    if (x == n) { //走到最后一行 且n皇后都放好的时候
        if (s == n) { // 如果找到方案的话
        for (int i = 0; i < n; i ++) {
            puts(g[i]);//puts输出二维数组 输出每一行如何就会自动换行 
            }//puts遍历字符串这个语法不懂看下
        puts("");
        }
        return; //返回调用函数进行执行
    }

    dfs(x, y + 1, s);//不放皇后  并且访问右节点

    // 判断皇后能否放在这格
    if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) {
        g[x][y] = 'Q';//放皇后 然后把
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;

        dfs(x , y + 1, s + 1);//放置皇后,找下一层的

        //回溯的时候 记得恢复现场 ↓ 
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = false; 
        g[x][y] = '.';
    }
}

int main () {
    cin >> n;
    for (int i = 0; i < n;i ++) {
        for (int j = 0; j < n; j ++) {
            g[i][j] = '.'; //初始化全部空格子
        }
    }
    dfs(0,0,0); //从第一行开始找

    return 0;
}

②、代码剖析

③、row数组的理解

在这里插入图片描述

④、dg[x + y] = udg[x - y + n]的理解

dg[x + y] = udg[x - y + n] 有的兄弟可能不理解其中x+y到底是什么意思?

✨3、思路二

#include <iostream>
using namespace std;
const int N = 20;//对角线元素 2n-1 取20防止越界 
int n;
char g[N][N]; //存储图
bool col[N], dg[N], udg[N]; //udg 副对角线 /
//英语单词 column 列   diagonal 主角线 \ 


void dfs (int x) { 

    if (x == n) { // 如果找到方案的话
        for (int i = 0; i < n; i ++) {
            puts(g[i]);//puts输出二维数组 输出每一行如何就会自动换行
        }
        puts("");   
        return; //返回调用函数进行执行
    }
    /* puts语句不理解 可以看下面这个 作用是一样的
        if (x == n) {
            for (int i = 0; i < n; i ++) {
                for (int j = 0; j < n; j ++) {
                    cout << g[i][j];
                }
                cout << endl;
            }
            cout << endl ;
            return;
        }
    */
    //x:行  y:列
    for (int y = 0; y < n; y ++) {
     	// 剪枝(提前判断当前方案已经错误,不再继续往下搜索,提高算法效率) 
        // 判断皇后能否放在这格  
        if (!col[y] && !dg[x + y] && !udg[n - x + y]) {
            g[x][y] = 'Q'; 
            col[y] = dg[x + y] = udg[n - x + y] = true;
        
            dfs(x + 1);//找下一层的

            //回溯的时候 记得恢复现场 
            col[y] = dg[x + y] = udg[n - x + y] = false; 
            g[x][y] = '.';
        }
    }
}

int main () {
    cin >> n;
    for (int i = 0; i < n;i ++) {
        for (int j = 0; j < n; j ++) {
            g[i][j] = '.'; //初始化全部空格子
        }
    }
    dfs(0); //从第一行开始找[0:下标]

    return 0;
}

🌟四、同类习题分享

🌟五、结尾:

举报

相关推荐

0 条评论