首页 > 编程语言 >【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字

【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字

时间:2023-05-07 20:32:45浏览次数:47  
标签:输出 843 int dfs 算法 数组 对角线 皇后 AcWing

n-皇后问题是一个经典的dfs深度优先遍历的题目,在题解这一题之前,将由浅入深,先讲解一个n-皇后问题的母题。-------AcWing 842. 排列数字  

[AcWing 842]. 排列数字

题目概述

给定一个整数 n,将数字 1∼n排成一排,将会有很多种排列方法。

现在,请你按照字典序将所有的排列方法输出。

输入格式

共一行,包含一个整数 n。

输出格式

按字典序输出所有排列方案,每个方案占一行。

数据范围

1≤n≤7

输入样例:

3

输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

题解思路:

重要的是搜索顺序,用什么样的顺序进行遍历,观察数据发现,没有重复的,说明在遍历搜索的时候是要标记那些是被选过,哪一些没有被选过的,当我选出的数需要放到一个数组里面,当长度和n相等说明这个选出的所有数就是一个排列,直接输出。下图就是算法递归过程中往下找和往上回溯的过程图:

【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字_n-皇后问题

算法:

  • 用 val 数组保存排列,当排列的长度为 n 时,是一种方案,输出。
  • 用 state 数组表示数字是否用过。当 state[i] 为 1 时:i 已经被用过,state[i] 为 0 时,i 没有被用过。
  • dfs(i) 表示的含义是:在 val[i] 处填写数字,然后递归的在下一个位置填写数字。
  • 回溯:第 i 个位置填写某个数字的所有情况都遍历后, 第 i 个位置填写下一个数字。

代码:

#include<iostream>
using namespace std;
int n;
const int N=10;
int val[N];   //用来存选的数
int state[N];   //标记状态

void dfs(int u)
{
    if(u>n)
    {
        for(int i=1;i<=n;i++)
        {
            cout<<val[i]<<" ";
        }
        cout<<endl;
    }

    for(int i=1;i<=n;i++) //从1~n中选数字
    {
        if(!state[i])  //没被选过的进入
        {
            val[u]=i;  //在u位置放i
            state[i]=1;
            dfs(u+1);
            state[i]=0; //回溯 到了dfs下一个 i是没有被选过的得还原
        }
    }

}

int main()
{
    cin>>n;
    dfs(1);
}

输出结果:

【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字_n-皇后问题_02



[AcWing] 843. n-皇后问题

这个问题是上面排列数字的升级版,模板也是一样,上一题是要满足不能重复出现的排列,n皇后就是在同行、同列、正反对角线都不能有皇后的组合方案。

题目概述

n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互打到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字_排列数字_03

现在给定整数 n,请你输出所有的满足条件的棋子摆法。

输入格式

共一行,包含整数 n。

输出格式

每个解决方案占 n行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。每个方案输出完成后,输出一个空行。

注意:行末不能有多余空格。

输出方案的顺序任意,只要不重复且没有遗漏即可。

数据范围

1≤n≤9

输入样例:

4

输出样例:

.Q..
...Q
Q...
..Q.

..Q.
Q...
...Q
.Q..

题解思路:

核心解题思路和排列数字相似,用一个数组来存整个棋盘,需要满足行列正反对角线都不能有皇后,所以也设置标志数组true、false来进行判断是否有皇后。当dfs(u)的u==n,那么就是相当于找到了一组解,那么就输出出来,如果标志数组发现没有皇后,那么把Q放进存储数组,然后标志数组进行更新为true。接着递归u+1,一定要注意是回溯回去之后要把存储数组这个给还原,目前是我递归进来的,我在这个状态下是被设置为皇后Q,当我递归开始回溯后,回到我当前状态的上一个状态我还是'.',所以要还原。

【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字_n-皇后问题_04

算法:

  • 用 arr数组保存棋盘,当dfs(u)的长度为 n 时,是一种方案,输出。
  • 用 col[N] dg[N] udg[N] 数组表示这个位置是否有皇后。当 col[N]&& dg[N]&& udg[N] 为true ,那么这个位置的行还有正反对角线是存在皇后的, 为false ,那么这个位置的行还有正反对角线没有皇后可以放。
  • dfs(i) 表示的含义是:在 arr[i] 处填写放皇后Q,然后递归的在下一个位置填写下个皇后Q。
  • 回溯:第 i 个位置放皇后的所有情况都遍历后, 第 i 个位置填写下一个皇后。就得恢复现场,恢复到我上一个状态的时候是啥。

代码:

#include<iostream>
using namespace std;
int n;
const int N=20;
char arr[N][N];   // 放数据,用于存储棋盘
bool col[N],dg[N],udg[N];  // 限制行、正对角线、反对角线 

void dfs(int u)  // 搜索函数,参数u表示当前处理到第几行
{
    if(u==n)  // 当前处理到第n行,说明已经找到一组解,输出并返回
    {
        for(int i=0;i<n;i++) puts(arr[i]);  // 输出棋盘的一种解
        puts("");  // 换行
        return;
    }

    for(int i=0;i<n;i++)  // 枚举放在第u行的皇后的列号
    {
        if(!col[i]&&!dg[u+i]&&!udg[i-u+n])   // 判断这个位置是否可行
        // 判断此列,正负对角线是否有另一枚皇后,如果没有则可以放置皇后
        {
            arr[u][i]='Q';  // 将这个位置放上皇后
            col[i]=dg[i+u]=udg[i-u+n]=true;  // 更新限制条件
            dfs(u+1);  // 继续搜索下一行
            col[i]=dg[i+u]=udg[i-u+n]=false;  // 回溯时要恢复限制条件
            arr[u][i]='.';  // 回溯时要恢复棋盘状态
        }
    }
}

int main()
{
    cin>>n;  // 输入皇后数量
    for(int i=0;i<n;i++)  // 初始化棋盘,全部置为'.'表示无皇后
    {
        for(int j=0;j<n;j++)
        {
            arr[i][j]='.';
        }
    }
    dfs(0);  // 从第0行开始搜索
    return 0;
}

对对角线dg[u+i] 和udg[i-u+n]的理解:

以反对角线举例,i- u其实就是该点在对角线上的截距 由中学知识可知对角线方程为y = x + b,其中b表示截距也就是b = y - x(数组下标里面的东西),如果在不同行,但再同一对角线,经过方程计算得到的截距都是一样的,不懂就拿纸自己写一下,+n是为了防止负数产生, 因为数组下标是不可能为负数的,因为每个数都+n,他们映射到结果是一样的,不信你就换个比n大的数试试。


输出结果:

【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字_搜索_05

标签:输出,843,int,dfs,算法,数组,对角线,皇后,AcWing
From: https://blog.51cto.com/u_15831056/6252526

相关文章

  • 文心一言 VS chatgpt (15)-- 算法导论3.2 4~5题
    四、函数多项式有界吗?函数多项式有界吗?文心一言:chatgpt:对于第一个问题,函数是阶乘的形式,可以证明它是超多项式增长的,因此不是多项式有界的。对于第二个问题,函数的增长速度比慢很多。虽然不是多项式,但是它是多项式有界的,也就是说,存在一个多项式和常数,使得当足够大时......
  • C语言基础算法
    1、计算Fibonacci数列Fibonacci数列又称斐波那契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21。C语言实现的代码如下:/* Displaying Fibonacci sequence up to nth term where n is entered by user. */#include <stdio.h>int main(){i......
  • 基于双目图像三维建模算法的测量目标物体体积计算matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要         双目立体视觉(BinocularStereoVision)是机器视觉的一种重要形式,它是基于视差原理并利用成像设备从不同的位置获取被测物体的两幅图像,通过计算图像对应点间的位置偏差,来获取物体三......
  • 高密度城市路线规划的遗传优化算法的matlab仿真,城市点数量达到500个
    1.算法仿真效果matlab2022a仿真结果如下:  2.算法涉及理论知识概要       遗传算法GA把问题的解表示成“染色体”,在算法中也即是以二进制编码的串。并且,在执行遗传算法之前,给出一群“染色体”,也即是假设解。然后,把这些假设解置于问题的“环境”中,并按适者生存的原......
  • 算法 | 快速排序详解
    1快速排序基本思想从待排序记录序列中选取一个记录(随机选取)作为基点,其关键字设为key,然后将其余关键字小于key的记录移到前面,而将关键字大于key的记录移到后面,结果将待排序记录序列分为两个子表,最后将关键字key的记录插入到分界线的位置。这个过程称为一趟快速排序。经过这一趟......
  • 基础算法
    位运算拆解:例如龟速乘和快速幂。状态压缩:可以用一个数字表示一个状态,不够长还可以用bitset。龟速乘通过对数字的每一位进行拆分,将乘法变成加法。代码#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;llmul(lla,llb,llp){ llans=0; while(b){ ......
  • POJ2739 Sum of Consecutive Prime Numbers&&Acwing4938 连续质数之和
    方法:单调队列为什么是单调队列?因为这里让我们求连续的质数和,我们可以利用欧拉筛来维护质数,再利用单调队列来维护连续的质数。代码(POJ不支持C++11差评):#include<cstdlib>#include<cstring>#include<cstdio>#include<cctype>namespaceFastIo{ #definegcgetchar() #d......
  • m基于POCS算法的空域序列图像超分辨率重建matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:     2.算法涉及理论知识概要       随着信息处理技术和视觉通信技术的高速发展,人们获取的知识量爆炸式增长,因此迫切的要求完善的信息处理技术为人们提供更加方便、快捷服务。数字图像及及其相关技术是信息处理技......
  • acwing 4645. 选数异或
     输出yesnoyes no题意分析,给一串数组,再在每次提问时给出一个区间,l,r;求l,r区间内是否存在两个数,两数异或后值为给出的x;已知a^b=x-->a^x=b;思路:1,把每个数异或x,存在另一个数组(b)里,暴力搜索,看区间内b数组内数字是否有等于a数组内数字,TLE2.记录下标,比较每个......
  • 为什么说程序=算法+数据结构
    听到`程序=数据结构+算法`,可能很多同学觉得不太好理解。那么如果我说`程序=变量+业务`,是不是就好理解了。其实我们开发一款应用程序,就是定义一些变量,然后围绕这些变量进行业务的开展。理解了,我们再来说。变量只是统称,我们可能针对不同的业务使用不同的变量类型(数据结构),来......