递归/回溯:八皇后问题N-Queens
N皇后问题是计算机科学中最为经典的问题之一,该问题可追溯到1848年,由国 际西洋棋棋手马克斯·贝瑟尔于提出了8皇后问题。
将N个皇后放摆放在N*N的棋盘中,互相不可攻击,有多少种摆放方式,每种摆 放方式具体是怎样的?
8皇后即 8*8的棋盘中,将8个皇后放置在棋盘上,且皇后之间无法俩俩攻击到对方。
关于国际象棋中皇后的实力:国际象棋棋局中实力最强的一种棋子,也是最容易被吃掉的棋子。后可横直斜走,且格数不限
类似4*4的棋盘上,有如下两种皇后的放置方法:
.Q..
...Q
Q...
..Q...Q.
Q...
...Q
.Q..
分析:
N*N的棋盘放置N个皇后,即至少每一行需要一个皇后;
- 将一个皇后放置到棋盘上之后,棋盘如何演变(一个皇后放到棋盘,她的影响区域为上,下,左,右,左上,左下,右上,右下)
- 针对每一个皇后,如何能够确认下一个皇后,以及下下一个皇后。。。直到能够放置N个皇后的棋盘分布?
针对问题一,我们可以实现如下算法:
针对棋盘打标:
void mark_queen(int x, int y, std::vector<std::vector<int> > &mark) {/*维护两个方向数组可以取到皇后的八个方向即可这里定义了const型是为了节省内存,即整个进程代码运行期间,此时的const两个数组是存放在常量内存区,且定义为了static,则整个代码仅仅会有一份拷贝*/static const int dx[] = {0,0,-1,1,-1,1,-1,1}; static const int dy[] = {-1,1,0,0,-1,-1,1,1}; if (x < 0 || x > mark.size() || y < 0 || y > mark.size()) {return ;}mark[x][y] = 1;for (int i = 0;i < mark.size(); ++i) {for (int j = 0;j < 8; ++j) {int new_x = x + i * dx[j];int new_y = y + i * dy[j];if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {mark[new_x][new_y] = 1;}}}
}
回到问题2上,我们想要获取棋盘上能够放置皇后的方法的个数以及具体的放置位置;
可以先尝试一个一个放,当然这放置可以按照行放,也可以按照列放(八皇后问题最终的表现形式就是每行只能有一个,每一列只能有一个)。
我们这里的放置皇后的方式都按照行放,第一行第一个:
Q | 1 | 1 | 1 |
---|---|---|---|
1 | 1 | 0 | 0 |
1 | 0 | 1 | 0 |
1 | 0 | 0 | 1 |
接下来皇后的放置的规则肯定就是在不能被第一个Q影响的情况下放置了,我们这里仍然按照行进行放置,放第二个,如下红色1则为重新放置后打入的标记
Q | 1 | 1 | 1 |
---|---|---|---|
1 | 1 | Q | 1 |
1 | 1 | 1 | 1 |
1 | 0 | 1 | 1 |
再次进行放置,发现第三行已经没有位置可以放了,此时可以定论,最开始的第一次放置位置不合理,需要进行回溯,回溯到第一次放置Q之前棋盘的位置,即
0 | 0 | 0 | 0 |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
综上过程我们可以知道我们算法实现有以下几个点
- 按行(或者列)进行棋盘遍历,每一次放置一个皇后,并对皇后区域进行打标
- 以上过程需要递归完成,递归过程中发现无法达到N*N放置N个皇后时即终止递归,并回滚棋盘状态为第一次放置皇后之前的棋盘状态。
实现算法如下(文末有完整测试代码):
/*标记棋盘放置皇后的数组*/
void mark_queen(int x, int y, std::vector<std::vector<int> > &mark) {static const int dx[] = {0,0,-1,1,-1,1,-1,1};static const int dy[] = {-1,1,0,0,-1,-1,1,1};if (x < 0 || x > mark.size() || y < 0 || y > mark.size()) {return ;}mark[x][y] = 1;for (int i = 0;i < mark.size(); ++i) {for (int j = 0;j < 8; ++j) {int new_x = x + i * dx[j];int new_y = y + i * dy[j];if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {mark[new_x][new_y] = 1;}}}
}/*递归+回溯棋盘状态*/
void generate(int k, int n, std::vector<string> &location, //用字符表示放置策略std::vector<std::vector<string>> &result, //最终的放置策略的汇总std::vector<std::vector<int> > &mark) { //保存每一次放置皇后的棋盘状态if (k == n) { //结束条件就是发现当前放置策略支持N个皇后result.push_back(location);return;}/*按行遍历*/for (int i = 0;i < n; ++i) {/*备份初始棋盘状态*/std::vector<std::vector<int>> tmp_mark = mark;/*放置位置就是没有被打标的位置,即不会被其他皇后影响的位置*/if (mark[k][i] == 0) {/*放置一个皇后,针对其进行打标*/mark_queen(k, i, mark);location[k][i] = 'Q';generate(k+1, n, location, result, mark);/*递归之后回滚到最初备份的状态*/mark = tmp_mark;location[k][i] = '.';}}
}
/*初始化棋盘*/
std::vector<std::vector<string> > solve_N_queen(int n) {std::vector<std::vector<int> > mark;std::vector<std::vector<string> > result;std::vector<string> location;for (int i = 0;i < n; ++i) {mark.push_back(std::vector<int> ());for (int j = 0;j < n; ++j) {mark[i].push_back(0);}location.push_back("");location[i].append(n,'.');}generate(0,n,location,result,mark);return result;
}
测试代码如下:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>/*
N皇后问题是计算机科学中最为经典的问题之一,该问题可追溯到1848年
由国际西洋棋棋手马克斯·贝瑟尔于提出了8皇后问题。 将N个皇后放摆放在N*N的棋盘中,互相不可攻击,有多少种摆放方式,每种摆 放方式具体是怎样的?类似 N = 4
那么如下输出
solution1:
.Q..
...Q
Q...
..Q.solution2:
..Q.
Q...
...Q
.Q..
*/using namespace std;/*标记棋盘放置皇后的数组*/
void mark_queen(int x, int y, std::vector<std::vector<int> > &mark) {static const int dx[] = {0,0,-1,1,-1,1,-1,1};static const int dy[] = {-1,1,0,0,-1,-1,1,1};if (x < 0 || x > mark.size() || y < 0 || y > mark.size()) {return ;}mark[x][y] = 1;for (int i = 0;i < mark.size(); ++i) {for (int j = 0;j < 8; ++j) {int new_x = x + i * dx[j];int new_y = y + i * dy[j];if (new_x >= 0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {mark[new_x][new_y] = 1;}}}
}void generate(int k, int n, std::vector<string> &location, std::vector<std::vector<string>> &result, std::vector<std::vector<int> > &mark) {if (k == n) {result.push_back(location);return;}for (int i = 0;i < n; ++i) {std::vector<std::vector<int>> tmp_mark = mark;if (mark[k][i] == 0) {mark_queen(k, i, mark);location[k][i] = 'Q';generate(k+1, n, location, result, mark);mark = tmp_mark;location[k][i] = '.';}}
}std::vector<std::vector<string> > solve_N_queen(int n) {std::vector<std::vector<int> > mark;std::vector<std::vector<string> > result;std::vector<string> location;for (int i = 0;i < n; ++i) {mark.push_back(std::vector<int> ());for (int j = 0;j < n; ++j) {mark[i].push_back(0);}location.push_back("");location[i].append(n,'.');}generate(0,n,location,result,mark);return result;
}int main(int argc, char const *argv[])
{int n;cin >> n;std::vector<std::vector<string>> result; result = solve_N_queen(n);cout << "num of method is " << result.size() << endl;cout << "method is " << endl;for (int i = 0; i < result.size(); ++i) {for (int j = 0;j < result[i].size(); ++j) {cout << result[i][j];cout << endl;}cout << endl;}return 0;
}
编译:g++ -std=c++11 test.c -o test
输出如下:
#输入
8
#输出
num of method is 92
method is
Q.......
....Q...
.......Q
.....Q..
..Q.....
......Q.
.Q......
...Q....
#以下输出较多,可自行编译查看
...#输入
4
#输出
num of method is 2
method is
.Q..
...Q
Q...
..Q...Q.
Q...
...Q
.Q..
递归/回溯:八皇后问题N-Queens相关推荐
- 有趣的数据结构算法12——利用递归解决八皇后问题
有趣的数据结构算法12--利用递归解决八皇后问题 题目复述 解题思路 实现代码 GITHUB下载连接 本次教程主要讲述如何利用递归解决八皇后问题,它和汉诺塔一样让人很难过. 题目复述 据说西洋棋手都具 ...
- 递归--基于回溯和递归的八皇后问题解法
八皇后问题是在8*8的棋盘上放置8枚皇后,使得棋盘中每个纵向.横向.左上至右下斜向.右上至左下斜向均只有一枚皇后.八皇后的一个可行解如图所示: ...
- 递归实现八皇后并生成皇后位置图
记录一下解决八皇后问题的代码 1.枚举类型 #include<string> #include<iostream> using namespace std; static in ...
- 递归解决八皇后问题-小昝
引言 由于大学课堂中数据结构中并没有讲一些常见的算法,只是讲的比较简单的定义.所以拿出来暑假时间去研究经典的算法.本文章是研究的八皇后问题.八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 ...
- 【数据结构算法】递归:八皇后问题
八皇后 八皇后问题就是说如下图所示的国际象棋的棋盘中,放入8个皇后,所谓皇后就是国际象棋中的一个角色,它的功能就是能够打掉与它同一行同一列同一斜排的棋子,并且打击距离是整个棋盘.我们的任务就是在棋盘中 ...
- 递归设计--八皇后+神奇的口袋+数列+吃糖果
2019.01.26 是日晴朗,纪念下放假以来第一次9点起,最近怎么越活越回去呢,别再患得患失啦,过好当下就行哟~ 本文主要是递归设计练习的总结,包含以下内容(难度依次递减) 八皇后(N皇后):全排列 ...
- C语言递归解决八皇后问题
八皇后问题,任意两个皇后都不能处于同一行.同一列或同一斜线上. 在8x8的格子上,我们可以约定每一个皇后都占一行,这样就不会出现行冲突.任何在一次将一个皇后放在一列上,判断是否与前面的皇后有冲突,直到 ...
- 八皇后问题 matlab,Matlab 递归求解八皇后问题
这是递归版本,随后会给出其他版本 function Queens % 8皇后问题的递归法求解 sol = 1; % 解的个数 queen = zeros(8); % 8*8的棋盘 saferows = ...
- 回溯算法 | 追忆那些年曾难倒我们的八皇后问题
文章收录在公众号:bigsai 更多精彩干货敬请关注! 前言 说起八皇后问题,它是一道回溯算法类的经典问题,也可能是我们大部分人在上数据结构或者算法课上遇到过的最难的一道题-- 第一次遇到它的时候应该 ...
- 八皇后时间复杂度_回溯算法 | 追忆那些年曾难倒我们的八皇后问题
文章收录在公众号:bigsai,关注更多干货和学习资源 记得点赞.在看 前言 说起八皇后问题,它是一道回溯算法类的经典问题,也可能是我们大部分人在上数据结构或者算法课上遇到过的最难的一道题-- 在这里 ...
最新文章
- 官宣!微软宣布桌面版 Edge将基于Chromium进行开发\n
- html支持的语音文件格式,html5中如何设置audio支持音频格式
- Java内存模型深度解析:锁--转
- 浅谈python的深浅拷贝
- linux系统预定义变量有哪些,C++中几个预定义变量的介绍
- 定时器的实现原理 不消耗cpu_空闲CPU在做什么?
- LabView学习笔记(十):条件结构
- mysql 周 获取日期_MySQL获取日期周、月、天,生成序号
- ★★★★★手把手教你如何利用凤凰实现破 解后台权限以及升级固件(刷机)★★★★★
- Himawari-8葵花数据的python读取和matlab读取
- 计算机格式化的作用,怎样把电脑格式化 电脑格式化方法【图文】
- 【STMT】等价类划分法
- unity2d 投影_Unity Projector 投影器原理以及优化
- brpc中的协程bthread源码剖析(一):Work Stealing以及任务的执行与切换
- 修复VSAN无法看到的主机磁盘
- P1347 排序(topo)
- 初识Python必看基础知识~ 续(3)
- speedoffice文档中如何快速撤回到上一步操作
- pygame小项目 ~ 3 :Python完成简易飞机大战
- YAHOO工具库提供的方法
热门文章
- mac 端口转发方案
- 《OpenCV3编程入门》学习笔记8 图像轮廓与图像分割修复(二)寻找物体的凸包
- usaco ★Zero Sum 和为零
- linux 禅道服务器,Linux下如何搭建禅道项目管理软件
- ipad html 自定义裁剪图片大小,移动端图片裁剪上传插件 Mavatar.js(原创)
- ajax调取json接口,通过 Ajax 调取后台接口将返回的 json 数据绑定在页面上
- python刷题笔记怎么改_python面试题刷题笔记1 - 10
- 数据存储方式_寻找要操作数据的存储地址的过程称为寻址,几种寻址的方式分享...
- java录排名怎么写_面试官:Java排名靠前的工具类你都用过哪些?
- 服务器登录中心,为数据中心配置登陆服务器来进行远程访问