【一百】【算法分析与设计】N皇后问题常规解法+位运算解法

N皇后问题

链接:登录---专业IT笔试面试备考平台_牛客网 来源:牛客网

题目描述

给出一个n×nn\times nn×n的国际象棋棋盘,你需要在棋盘中摆放nnn个皇后,使得任意两个皇后之间不能互相攻击。具体来说,不能存在两个皇后位于同一行、同一列,或者同一对角线。请问共有多少种摆放方式满足条件。

输入描述:

一行,一个整数n(1≤n≤12)n(1\le n \le 12)n(1≤n≤12),表示棋盘的大小。

输出描述:

输出一行一个整数,表示总共有多少种摆放皇后的方案,使得它们两两不能互相攻击。

示例1

输入

复制4

4

输出

复制2

2

常规解法

复制代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

#define int long long
#define endl '\n'
#define Fast() ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

#define p pair<int,int>
#define ff first
#define ss second 
#define pb push_back
#define ppb pop_back

#define ltu(i,a,b) for(int i=a;i<=b;i++) // 定义从a到b的循环
#define utl(i,a,b) for(int i=a;i>=b;i--) // 定义从a到b的倒序循环
#define tests() int t;cin>>t;while(t--) // 读取测试次数并循环

int n; // 棋盘的大小
int ret=0; // 解的数量
vector<bool> visited1; // 列的标记数组
vector<bool> visited2; // 左下到右上的斜线标记数组
vector<bool> visited3; // 右下到左上的斜线标记数组

void dfs(int i){ // 深度优先搜索函数,i表示当前行
    ltu(j,1,n){ // 遍历第i行的每一列
        if(!visited1[j]&&!visited2[j-i+n]&&!visited3[j+i]){ // 如果第j列和两条斜线都没有被占用
            if(i==n){ // 如果已经放到最后一行
                ret++; // 解的数量加一
                continue; // 继续下一次循环
            }
            visited1[j]=visited2[j-i+n]=visited3[j+i]=true; // 标记当前列和斜线
            dfs(i+1); // 递归调用下一行
            visited1[j]=visited2[j-i+n]=visited3[j+i]=false; // 回溯,取消标记
        }
    }
}

void solve(){ // 解决函数
    ret=0; // 重置解的数量
    visited1.assign(n+1,0); // 初始化列标记数组
    visited2.assign(2*n+1,0); // 初始化左下到右上的斜线标记数组
    visited3.assign(2*n+1,0); // 初始化右下到左上的斜线标记数组
    dfs(1); // 从第一行开始搜索
    cout<<ret<<endl; // 输出解的数量
}

signed main(){ // 主函数
    Fast(); // 加速输入输出
    
    cin>>n; // 读取棋盘大小
    solve(); // 调用解决函数
}

位运算解法1

复制代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

#define int long long // 定义 int 为 long long 类型
#define endl '\n' // 定义 endl 为换行符
#define Fast() ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); // 快速输入输出

#define p pair<int,int> // 定义 p 为一对整数
#define ff first // 定义 ff 为 first
#define ss second // 定义 ss 为 second 

#define ltu(i,a,b) for(int i=a;i<=b;i++) // 定义从 a 到 b 的递增循环
#define utl(i,a,b) for(int i=a;i>=b;i--) // 定义从 a 到 b 的递减循环
#define tests() int t;cin>>t;while(t--) // 定义测试次数循环

int n; // 定义 n
int ret=0; // 定义 ret 并初始化为 0
int col, leftt, rightt; // 定义 col, leftt, rightt 记录有皇后的位置

// 深度优先搜索函数
void dfs(int i, int col, int leftt, int rightt) {
    if (i == n + 1) { // 如果已经放置完所有皇后
        ret++; // 计数增加
        return; // 返回上一层
    }
    // 从第 0 列到第 n-1 列尝试放置皇后
    ltu(j, 0, n-1) {
        // 检查第 j 列,左斜和右斜是否被攻击
        bool temp = (col & (1 << j)) | (leftt & (1 << (i - j + n))) | (rightt & (1 << (i + j)));
        if (!temp) { // 如果当前位置没有被攻击
            // 递归调用下一行,更新 col, leftt 和 rightt
            dfs(i + 1, col | (1 << j), leftt | (1 << (i - j + n)), rightt | (1 << (i + j)));
        }
    }
}

// 解决问题的函数
void solve() {
    col = leftt = rightt = 0; // 初始化 col, leftt 和 rightt
    dfs(1, col, leftt, rightt); // 调用 dfs 函数从第 1 行开始
    cout << ret << endl; // 输出结果
}

signed main() {
    Fast(); // 快速输入输出
    
    cin >> n; // 输入 n
    solve(); // 调用 solve 函数
}

位运算解法2

复制代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

#define int long long // 定义 int 为 long long 类型
#define endl '\n' // 定义 endl 为换行符
#define Fast() ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); // 快速输入输出

#define p pair<int,int> // 定义 p 为一对整数
#define ff first // 定义 ff 为 first
#define ss second // 定义 ss 为 second
#define pb push_back // 定义 pb 为 push_back
#define ppb pop_back // 定义 ppb 为 pop_back

#define ltu(i,a,b) for(int i=a;i<=b;i++) // 定义从 a 到 b 的递增循环
#define utl(i,a,b) for(int i=a;i>=b;i--) // 定义从 a 到 b 的递减循环
#define tests() int t;cin>>t;while(t--) // 定义测试次数循环

int n; // 定义 n
int ret=0; // 定义 ret 并初始化为 0
int col,leftt,rightt; // 定义 col, leftt, rightt 记录有皇后的位置
int aim=0; // 定义 aim 并初始化为 0

// 深度优先搜索函数
void dfs(int i,int col,int leftt,int rightt){
    int temp=col|leftt|rightt; // 计算当前所有被攻击的位置
    temp=~temp; // 取反得到可以放置皇后的位置
    temp&=aim; // 只保留有效位

    // 当 temp 不为 0 时
    while(temp){
        int lowbit=temp&(-temp); // 取出最低位的 1
        temp^=lowbit; // 将最低位的 1 置为 0
        if(i==n){ // 如果已经到最后一行
            ret++; // 计数增加
            continue; // 继续下一步
        }
        // 递归调用下一行,更新 col, leftt 和 rightt
        dfs(i+1,col|lowbit,(leftt|lowbit)<<1,(rightt|lowbit)>>1);
    }
    
}

// 解决问题的函数
void solve(){
    ret=0; // 初始化 ret
    col=leftt=rightt=0; // 初始化 col, leftt 和 rightt
    aim=(1<<n)-1; // 初始化 aim,将前 n 位设为 1
    dfs(1,col,leftt,rightt); // 调用 dfs 函数从第 1 行开始
    cout<<ret<<endl; // 输出结果
}

signed main(){
    Fast(); // 快速输入输出
    
    cin>>n; // 输入 n
    solve(); // 调用 solve 函数
    
}

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

相关推荐
passer__jw76711 分钟前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode
Ocean☾17 分钟前
前端基础-html-注册界面
前端·算法·html
顶呱呱程序25 分钟前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
爱吃生蚝的于勒1 小时前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~1 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
王哈哈^_^1 小时前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
星沁城1 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
脉牛杂德2 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz2 小时前
STL--哈希
c++·算法·哈希算法
CSUC2 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++