c++回溯算法——N皇后、2N皇后问题

本文详细解析了N皇后问题的两种经典场景及其解决方案。首先介绍了如何使用深度优先搜索算法解决标准N皇后问题,即在n×n的棋盘上放置n个皇后,确保彼此不受攻击。随后,探讨了更复杂的2N皇后问题,考虑了棋盘上某些位置不可用的情况,并展示了如何通过改进的深度优先搜索算法找到所有可能的放置方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

N皇后
问题描述:

  • 在n×n格的棋盘上放置彼此不受攻击的n个皇后。
  • 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n皇后问题等价于在n×n格的棋盘上放置n个皇后,任何两个皇后不放在同一行或同一列或同一斜线上。
  • 编程要求:找出一个n×n格的棋盘上放置n个皇后并使其不能互相攻击的所有方案。
    -在这里插入图片描述
#include <bits/stdc++.h>
using namespace std;
#define NUM 20
int n;			//棋盘的大小
int x[NUM];		//解向量
int sum;		//当前已经找到的可行方案数
//形参t是回溯的深度
inline bool Place(int t)
{
    int i;
    for(i=1;i<t;i++)
    {
    /*1.由于每一列只放置一个皇后,所以不会出现同列的问题,不用判断合法性。
    2.对于每一行,假设已经放置到t列,只要判断 ,i=1, 2, …, t-1互不相同即可。
   3. 对于对角线的判断,可以看成是斜率为±1的两条直线,经过两点(i,x[i])和(t,x[t]):
   |t-i/(x[t]-x[i])|=1;(t-i)的绝对值=(x[i]-x[t])的绝对值
    */
        if((abs(t-i)==abs(x[i]-x[t]))||(x[i]==x[t]))
            return false;
    }
     return true;
}
//形参t是回溯的深度,从1开始
void Backtrack(int t)
{
    int i;
    //到达叶子节点,获得一个方案,累加
    if(t>n)
    {
        sum++;
        for(i=1;i<=n;i++)
        {//输出该方案
            cout<<x[i]<<" ";
        }
        cout<<endl;
    }else
        for(i=1;i<=n;i++)
        {
            x[t]=i;
            if(Place(t))Backtrack(t+1);
        }

}
int main()
{
    cin>>n;
    Backtrack(1);
    cout<<"Total:"<<sum<<endl;
    return 0;
}
/*DFS深度优先搜索算法(depth first search):一种用于遍历或搜索树或图的算法。
 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
 当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,
 搜索将回溯到发现节点v的那条边的起始节点。
 整个进程反复进行直到所有节点都被访问为止。
 属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。*/

2N皇后
问题描述:
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
  输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
  输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0

#include <bits/stdc++.h>
using namespace std;
const int maxn=9;
int n;
int Q[maxn][maxn];
int black[maxn]={0};
int white[maxn]={0};
int sum;//当前已经找到的可行方案数

bool placeBlack(int t)
{
    for(int i=1;i<t;i++)
    {
        if(abs(black[i]-black[t])==abs(i-t)||black[i]==black[t])
            return false;
    }
    return true;
}
bool placeWhite(int t)
{
    for(int i=1;i<t;i++)
    {
        if(abs(white[i]-white[t])==abs(i-t)||white[i]==white[t])
            return false;
    }
    return true;
}
void dfs_white(int t)
{
    if(t>n)
    {
        sum++;
    }
    for(int i=1;i<=n;i++)
    {
        if(black[t]==i)//表示第t列的第i行位置已经被黑皇后占用
            continue;
        if(Q[t][i]==0)//判断前提条件是否成立
            continue;
        white[t]=i;//把第t列的白皇后放在i行
        if(placeWhite(t))dfs_white(t+1);//如果可以放,则递归
    }
}
void dfs_black(int t)
{
    if(t>n)//黑皇后处理完再处理白皇后
    {
       dfs_white(1);
    }
    for(int i=1;i<=n;i++)
    {
        if(Q[t][i]==0)//判断前提条件是否成立
            continue;
        black[t]=i;//把第t列的黑皇后放在i行
        if(placeBlack(t))dfs_black(t+1);//如果可以放,则递归
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>Q[i][j];//定义棋盘
        }
    }
    sum=0;
    dfs_black(1);
    cout <<sum<< endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值