C++搜索N皇后问题

推荐刷题网站:http://47.108.154.71/icon-default.png?t=M0H8http://47.108.154.71/

N皇后问题题目:

在N*N(1<N<=9)的棋盘上放置N个皇后而彼此不受攻击(即在棋盘的任一行,任一列和任一对角线上不能放置2个皇后),编程求解所有的摆放方法。

 [输入格式] 
一个整数n(1<n<=9)
[输出格式]
若有解,输出若干行,每行n个数,依次表示第i个皇后的列号
若无解,输出 “no”
[输入样例]
4
[输出样例]
2    4    1    3
3    1    4    2

解题思路:

N皇后问题当中有个其妙的规律——各个斜边上的下标差或和相等。

由上图各位读者老爷可以发现斜边上的规律,当然我只列举了其中一条,其实其于斜边都有这种规律,老爷们可以自己去找找。 

但是,有没有想过,就这些规律可以有什么作用?

好问题,让我们再回顾一下题目要求即在棋盘的任一行,任一列和任一对角线上不能放置2个皇后

判断任意一行,任意一列和任意对角线上的皇后我们生活中一眼看过去就行了但是,电脑想要识别可不能像我们这样,所以我们找的这个规律就是用来当做行列的“身份证”的。

这样做的目的:通过行,列,对角线上的固定差值,来进行判断记录。

例如黑色线段上的格子,下标的和无论如何都是6。其他的斜边也都有自己一个固定的值,这就像是身份证一样,独一无二,所以判断时,只需判断重复“身份证”没有,即可实现不重复皇后的要求

可问题在于,有些斜边差回事负数,但是C++中下标最下是0,负数是违法的,为了避免这种情况可以统一给所有计算差或和时统一加上N,或者是7,毕竟图最大也就是7,(0,1,2,3,4,5,6,7,八个数)

代码实现

#include <bits/stdc++.h>//万能头文件可概括全部的头文件         
using namespace std;
long long sum=0;//sum是拿来计数的所以初始值是0. 
bool a[100],c[100],d[100]; 
int b[100],n;
int print()//这里是定义了一个输出函数 
{
    sum++;//用来记录方案数量 
    for(int i=1;i<=n;++i)cout<<b[i]<<" ";//输出当前的全部方案  
    cout<<endl;//换行 
}
int search(int i)
{
    for(int j=1;j<=n;++j)
    {
        if(a[j]==0&&c[i+j]==0&&d[i-j+7]==0)
		/*当画一个6*6的格子再根据题目进行分析时可发现: 
		每行每列每个斜边都有固定的差或者和,可以利用这个进行判断,存进数组 
		输出回溯……但有些数字差会是负数,且有的行列的差或和会跟其他行列的差或和 
		重复。所以就将全部数都加上一个7或n,在既保证不是负数
		也不重复情况下,又保证每行每列每个斜边上差跟和不一样
		这样就十分容易。 
		
		注:画图理解更佳*/ 
        {
            b[i]=j;//存放 。 
            a[j]=1;//等于1不再使用 。 
            c[i+j]=1;
            d[i-j+7]=1;
            if(i==n)//在满了不再有其他摆放方法时就将当前的方案输出 。 
                print();
            else
                search(i+1);
            a[j]=0;//回溯 撤回上次的记录 恢复保存结果之前的状态。 
            c[i+j]=0;//回溯 撤回上次的记录 恢复保存结果之前的状态。
            d[i-j+7]=0;//回溯 撤回上次的记录 恢复保存结果之前的状态。
        }
    }
}
int main()
{
    cin>>n;
    search(1);
    if(sum==0)cout<<"no";//如果无解 一个方案都没有 就按照题目要求输出no。 
    return 0;  
}

游客有好版

#include <bits/stdc++.h>//万能头文件可概括全部的头文件         
using namespace std;
long long sum=0;//sum是拿来计数的所以初始值是0. 
bool a[100],c[100],d[100]; 
int b[100],n;
int print()//这里是定义了一个输出函数 
{
    sum++;//用来记录方案数量 
    for(int i=1;i<=n;++i)cout<<b[i]<<" ";//输出当前的全部方案  
    cout<<endl;//换行 
}
int search(int i)
{
    for(int j=1;j<=n;++j)
    {
        if(a[j]==0&&c[i+j]==0&&d[i-j+7]==0)
        /*当画一个6*6的格子再根据题目进行分析时可发现: 
        每行每列每个斜边都有固定的差或者和,可以利用这个进行判断,存进数组 
        输出回溯……但有些数字差会是负数,且有的行列的差或和会跟其他行列的差或和 
        重复。所以就将全部数都加上一个7或n,在既保证不是负数
        也不重复情况下,又保证每行每列每个斜边上差跟和不一样
        这样就十分容易。 
        
        注:画图理解更佳*/ 
        {
            b[i]=j;//存放 。 
            a[j]=1;//等于1不再使用 。 
            c[i+j]=1;
            d[i-j+7]=1;
            if(i==n)//在满了不再有其他摆放方法时就将当前的方案输出 。 
                print();
            else
                search(i+1);
            a[j]=0;//回溯 撤回上次的记录 恢复保存结果之前的状态。 
            c[i+j]=0;//回溯 撤回上次的记录 恢复保存结果之前的状态。
            d[i-j+7]=0;//回溯 撤回上次的记录 恢复保存结果之前的状态。
        }
    }
}
int main()
{
    cin>>n;
    search(1);
    if(sum==0)cout<<"no";//如果无解 一个方案都没有 就按照题目要求输出no。 
    return 0;  
}

给个赞吧,谢谢啦…………

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值