一、啥是N皇后?先从四皇后入手

给定一个4x4的棋盘,要在棋盘上放置4个皇后。他们的位置有这样的要求,每一列,每一行,每一对角线都能有一个皇后。

你可能会对这个对角线有疑惑,其实就是每一个小正方形的对角线都不能有皇后。可以看图理解一下。


二、解题思想

设皇后k摆放在x[k]的位置上,注意数组下标从0开始,0<=k<n且0<=x[k]<n。

这里用数组下标以及对应的值,模拟了一个棋盘的行和列。这是比较奇妙的地方,不需要二维数组了。

算法:setQueen(n)

输入:皇后的个数n

输出:n皇后问题的解x[n]。解是一个数组。

  1. 初始化 k=0 初始化解向量 x[n] ={-1}
  2. 重复执行下面操作,摆放皇后k

    2.1. 把皇后k摆放在下一列的位置,即 x[k]++

    2.2. 如果皇后k摆放在x[k]位置发生冲突,则 x[k]++ 试探下一列,直到不冲突或 x[k] 出界

    2.3. 如果 x[k] 没出界并且所有皇后都摆放完毕,则输出一个解

    2.4. 如果 x[k] 没出界但有皇后尚未摆放,则 k++ ,转2.1摆放下一行的皇后

    2.5. 如果 x[k] 出界,则回溯,x[k]=-1 , k-- ,转2.1重新摆放上一行皇后

三、代码实现

#include <stdio.h>
#include <cstring>
#include <math.h>
class Queen
{
private:
int Place(int k);
int *x;
int num; public:
Queen(int n);
void setQueen();
void PrintQueen();
~Queen();
}; Queen::Queen(int n)
{
x = new int[n];
memset(x, -1, n); //-1表示尚未摆放皇后
num = n;
} Queen::~Queen()
{
delete[] x;
} void Queen::setQueen()
{
int k = 0, count = 0;
while (k >= 0) //摆放皇后k,注意0<=k<n
{
x[k]++; //在下一列摆放皇后k
while (x[k] < num && Place(k) == 1) //发生冲突
x[k]++; //皇后k试探下一列,超出num将会跳出
if (x[k] < num && k == num - 1) //得到一个解
{
printf("第%d个解:", ++count);
PrintQueen();
}
else if (x[k] < num && k < num - 1) //尚有皇后未摆放
k = k + 1; //准备摆放下一个皇后
else
x[k--] = -1; //重置x[k],回溯,重新摆放皇后k
}
} //放置皇后。在一个位置上放置皇后,然后将结果返回。
int Queen::Place(int k) //考察皇后k放置在x[k]列是否发生冲突
{
for (int i = 0; i < k; i++)
if (x[i] == x[k] || abs(i - k) == abs(x[i] - x[k])) //根据对角线原则
return 1; //冲突返回1
return 0; //不冲突返回0
} //打印皇后的解
void Queen::PrintQueen()
{
for (int i = 0; i < num; i++)
printf("%d\t", x[i] + 1);
printf("\n");
} int main(void)
{
int n;
printf("请输入皇后个数(n>=4):");
scanf("%d", &n);
Queen Q(n);
Q.setQueen();
return 0;
}

四、总结

这里面的代码是来自「数据结构C++王红梅版」

也知道了很多新颖的点

  1. 代码中就很好利用了数组下标作为形象上理解的一行
  2. 如何判定两个皇后是不是在同一对角线。也很好地利用了正方形的特性,皇后所在位置的行差与列差是否相等。
  3. 还有就是SetQueen()的逻辑结构,先用while循环摆放皇后,然后根据这个结果来判断是已经求解到了,还是该下一行或者回溯到上一行。

这里放一波我之前逻辑结构很混乱的代码(就可以求解到正确答案,但是输出的时机很难控制)

#include <stdio.h>
#include <string.h>
#include <math.h>
#define n 4 //设定n皇后的数目
int *x = new int[n]; void printA();
int place(int k);
int main(void)
{ memset(x, -1, sizeof(int) * n);
int k = 0;
while (k > -1)
{
x[k]++;
if (k < n && place(k) == 1) //不冲突,开始放置下一行 如果已经是最后一行呢?
{
if (k < n - 1)
k++;
}
else if (k < n || x[k] == n) //要回溯到上一行
{
x[k] = -1;
k--;
}
else if (k == n && x[k] < n)
{
//得到一组解答
printA();
}
} return 0;
} //在第k行放置皇后,返回1代表冲突,返回0代表不冲突
int place(int k)
{
for (; x[k] < n; x[k]++)
{
bool flag = true;
for (int i = 0; i < k; i++)
{
if (x[k] == x[i] || (abs(k - i) == abs(x[k] - x[i])))
{
flag = false;
break;
}
}
if (flag)
return 1;
}
return 0;
} void printA()
{
for (int i = 0; i < n; i++)
{
printf("%d ", x[i] + 1);
}
printf("\n");
}

N皇后求解。万万没想到,只用一个一维数组就搞定了。还体现了回溯。的更多相关文章

  1. 头条编程题 万万没想到之抓捕孔连顺 JavaScript

    [编程题] 万万没想到之抓捕孔连顺 时间限制:1秒 空间限制:131072K 我叫王大锤,是一名特工.我刚刚接到任务:在字节跳动大街进行埋伏,抓捕恐怖分子孔连顺.和我一起行动的还有另外两名特工,我提议 ...

  2. 字节跳动:[编程题]万万没想到之聪明的编辑 Java

    时间限制:1秒 空间限制:32768K 我叫王大锤,是一家出版社的编辑.我负责校对投稿来的英文稿件,这份工作非常烦人,因为每天都要去修正无数的拼写错误.但是,优秀的人总能在平凡的工作中发现真理.我发现 ...

  3. 一个int 数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它。能否只用一个额外数组和少量其它空间实现。

    一个int数组, 比如 array[],里面数据无任何限制,要求求出 所有这样的数array[i],其左边的数都小于等于它,右边的数都大于等于它.能否只用一个额外数组和少量其它空间实现. 分析:这题很 ...

  4. 把一个一维数组转换为in ()

    把一个一维数组转换为in()形式. function dbCreateIn($itemList) { if(empty($itemList )){ return " IN ('') &quo ...

  5. 万万没想到!ModelArts与AppCube组CP了

    摘要:嘘,华为云内部都不知道的秘密玩法,我悄悄告诉您! 双"魔"合璧庆双节 ↑开局一张图,故事全靠编 华为云的一站式开发平台ModelArts和应用魔方AppCube居然能玩到一起 ...

  6. 【问题总结】万万没想到,竟然栽在了List手里

    说明 昨天同事开发的时候遇到了一个奇怪的问题. 使用Guava做缓存,往里面存一个List,为了方便描述,称它为列表A,在另一个地方取出来,再跟列表B中的元素进行差集处理,简单来说,就像是下面这样: ...

  7. go 学习笔记之万万没想到宠物店竟然催生出面向接口编程?

    到底是要猫还是要狗 在上篇文章中,我们编撰了一则简短的小故事用于讲解了什么是面向对象的继承特性以及 Go 语言是如何实现这种继承语义的,这一节我们将继续探讨新的场景,希望能顺便讲解面向对象的接口概念. ...

  8. 文字转语音?我只用十行Python代码就搞定了!

    详细使用教程 1.没安装Python的小伙伴需要先安装一下 2.win+r输入cmd打开命令行,输入:pip install baidu-aip,如下安装百度AI的模块. 3.新建文本文档,copy如 ...

  9. 万万没想到,面试中,连 ClassLoader类加载器 也能问出这么多问题…..

    1.类加载过程 类加载时机 「加载」 将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存上创建一个java.lang.Class对象用来封装类在方法区内的数据 ...

随机推荐

  1. USB2.0协议学习笔记---USB工作过程(类的方法)

    前面学习了那么多的概念,这里需要记住一点分层概念即设备 ---> 配置 ---> 接口 ---> 端点,这种分层的概念结构 . 也可以理解为端点构成接口,接口组成配置,配置组成设备. ...

  2. CSS 定位 relative && absolute 问题?

    1 1 1 CSS 定位 relative && absolute 问题? 谁能解释一下,为什么div使用 relative是设置right,bottom 后,看不到div 呀,哪里多 ...

  3. js & Event Bus

    js & Event Bus global event handler (broadcast / trigger / emit / listen ) // 实现一个 EventBus类,这个类 ...

  4. HTML5 & custom element & template

    HTML5 & custom element & template template https://codepen.io/xgqfrms/pen/eYYExvp https://cs ...

  5. Jenkins Ansible GitLab 自动化部署

    Jenkins Ansible GitLab 自动化部署 DevOps https://www.cnblogs.com/yangjianbo/articles/10393765.html https: ...

  6. NGK又双叒叕送钱了!百万SPC空投不要错过!

    不知不觉,2021年已然到来.回顾过去一年,2020年币圈发生的事情真的是太多太多,比特币的持续暴涨,DeFi一波又一波的空投福利,都让我们见识了区块链的魅力!同样,2021年区块链市场的牛市仍然持续 ...

  7. 主键策略+mybayisPlus自动增长

    主键策略: 1.自动增长 有一点小缺陷:例如当一张表里的数据过于庞大时我们会进行分表操作,若是用自动增长策略,那么除了第一张表外的每一张表都必须知道上一张的表的的最后ID值.这个操作便会造成效率的变低 ...

  8. Spring-03 依赖注入(DI)

    Spring-03 依赖注入(DI) 依赖注入(DI) 依赖注入(Dependency Injection,DI). 依赖 : 指Bean对象的创建依赖于容器,Bean对象的依赖资源. 注入 : 指B ...

  9. Linux系统管理--part(1)

    Linux系统管理--part(1) Linux系统安装完毕,需要对Linux系统进行管理和维护,让Linux服务器能够真正英语于企业中 Linux运维的三个步骤安装.调试.启动 通过本篇文章,将学习 ...

  10. Newbe.Claptrap 框架入门,第一步 —— 开发环境准备

    Newbe.Claptrap 框架依托于一些关键性的基础组件和一些可选的辅助组件.本篇我们来介绍一下如何准备一个开发环境. Newbe.Claptrap 是一个用于轻松应对并发问题的分布式开发框架.如 ...