C++使用回溯法实现N皇后问题的求解
回溯法是个很无聊的死算方法,没什么技巧,写这篇博客主要原因是以前思路不太清晰,现在突然想用回溯法解决一个问题时,无法快速把思路转换成代码。
-------------------------------------------------------------------------------------------------------------------------------------
N-皇后问题描述:在N*N的棋盘上,每一行放置一个皇后,使得任意皇后之间不能互相攻击。求放置方法。
(因为国际象棋中皇后可以走横竖斜线,所以相当于是任意2个棋子不处在同一行、列或对角线)
思路是设解为四维向量x,第i行把皇后放在第x[i]列。(这里把行号列号均从0开始)然后像下面这样一个个找:
初始:x为空。令x[0] = 0,然后寻找第1个符合约束(简称“合法”)的x[1],可得x[1] = 2。再寻找第1个合法的x[2],发现无论是0、1、2、3都不行。于是就得回退了。
退到x[1],寻找下一个符合约束的x[1],即令x[1]=3,再继续找x[2]。若找到一组解则回退,寻找下一组解,一直到无法回退为止。
(比如x = { 1, 3, 0, 2 },添加x到解集中,之后回退寻找下一个合法的x[2]。此时发现1、2、3都不行,于是再回退,寻找下一个合法的x[1]。)
#include <stdio.h>
#include <vector>
#include <array>
using namespace std; template <int N>
class QueenProblem
{
public:
explicit QueenProblem()
{
for (int i = 0; i < N; i++)
x[i] = -1;
run();
} size_t size() const { return results.size(); }
const array<int, N>& operator[](size_t k) const { return results[k]; } private:
vector<array<int, N>> results; // 解集 // 解向量, (i,x[i])代表第i行第x[i]列放置皇后
// 其中行号和列号都是从0开始, 即范围为[0,N)
// x[i]=-1则代表第i行的位置并未确定
array<int, N> x; void run()
{
int k = 0;
while (k >= 0)
{
x[k]++; // 尝试新的位置
while (x[k] < N && !CheckRow(k))
x[k]++; if (x[k] == N) // 当前行无法放置皇后, 回溯
{
x[k--] = -1;
continue;
} if (k == N - 1) // 找到一组解, 将其添加到解集中并回溯寻找新的解
{
results.emplace_back(x);
x[k--] = -1;
}
else // 第0到k行合法, 尝试设置第k+1行的皇后
{
k++;
}
}
} // 假设第0到k-1行均成功放置皇后并且合法(即其中任意2个皇后不处于同一行/列/对角线)
// 判断第k行的放置方案是否合法, 若合法则返回true, 否则返回false
bool CheckRow(int k)
{
for (int i = 0; i < k; i++)
if (x[i] == x[k] || abs(x[i] - x[k]) == abs(i - k))
return false;
return true;
}
}; int main()
{
#define PrintNQueenSolNum(N) printf("%2d皇后的解的数量: %7ld\n", N, \
QueenProblem<N>().size());
PrintNQueenSolNum(1);
PrintNQueenSolNum(2);
PrintNQueenSolNum(3);
PrintNQueenSolNum(4);
PrintNQueenSolNum(5);
PrintNQueenSolNum(6);
PrintNQueenSolNum(7);
PrintNQueenSolNum(8);
PrintNQueenSolNum(9);
PrintNQueenSolNum(10);
PrintNQueenSolNum(11);
PrintNQueenSolNum(12);
PrintNQueenSolNum(13);
PrintNQueenSolNum(14);
PrintNQueenSolNum(15);
printf("其中, 4皇后的解为:\n");
QueenProblem<4> sol;
for (size_t i = 0; i < sol.size(); i++)
{
printf("第%d组解: ", i);
for (int x : sol[i])
printf("%d ", x);
printf("\n");
}
return 0;
}
直接贴包装后的代码了,编译期确定N,所以不支持运行时确定N是多少。算到15皇后就完了。
体现回溯法的核心代码就是成员函数run()
C++使用回溯法实现N皇后问题的求解的更多相关文章
- 回溯法解决N皇后问题(以四皇后为例)
以4皇后为例,其他的N皇后问题以此类推.所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子.在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平.竖直.以及45度 ...
- 用试探回溯法解决N皇后问题
学校数据结构的课程实验之一. 数据结构:(其实只用了一个二维数组) 算法:深度优先搜索,试探回溯 需求分析: 设计一个在控制台窗口运行的“n皇后问题”解决方案生成器,要求实现以下功能: 由n*n个方块 ...
- 递归回溯法求N皇后问题
问题描述:在一个NN(比如44)的方格中,在每一列中放置一个皇后,要求放置的皇后不在同一行,同一列,同一斜线上,求一共有多少种放置方法,输出放置的数组. 思路解析:从(1,1)开始,一列一列的放置皇后 ...
- 回溯法解n皇后问题
#include<bits/stdc++.h> using namespace std; int n,sum; int c[100]; void search(int cur){ if(c ...
- 回溯法之n皇后问题
package main import ( "fmt" "math" ) //判断第k行的某一列放置是否合法 func check(col []int, k i ...
- javascript实现数据结构: 树和二叉树的应用--最优二叉树(赫夫曼树),回溯法与树的遍历--求集合幂集及八皇后问题
赫夫曼树及其应用 赫夫曼(Huffman)树又称最优树,是一类带权路径长度最短的树,有着广泛的应用. 最优二叉树(Huffman树) 1 基本概念 ① 结点路径:从树中一个结点到另一个结点的之间的分支 ...
- python常用算法(7)——动态规划,回溯法
引言:从斐波那契数列看动态规划 斐波那契数列:Fn = Fn-1 + Fn-2 ( n = 1,2 fib(1) = fib(2) = 1) 练习:使用递归和非递归的方法来求解斐波那契数 ...
- 【Algorithm】回溯法与深度优先遍历的异同
1.相同点: 回溯法在实现上也是遵循深度优先的,即一步一步往前探索,而不像广度优先那样,由近及远一片一片地扫. 2.不同点 (1)访问序 深度优先遍历: 目的是“遍历”,本质是无序的.也就是说访问次序 ...
- 实现n皇后问题(回溯法)
/*======================================== 功能:实现n皇后问题,这里实现4皇后问题 算法:回溯法 ============================= ...
随机推荐
- python 从url中提取域名和path
使用Python 内置的模块 urlparse from urlparse import * url = 'https://docs.google.com/spreadsheet/ccc?key=bl ...
- JavaScript数字和字符串转换示例
http://www.jb51.net/article/48465.htm 1. 数字转换为字符串 a. 要把一个数字转换为字符串,只要给它添加一个空的字符串即可: 复制代码代码如下: var n = ...
- 十九、dbms_resource_manager(用于维护资源计划,资源使用组和资源计划指令)
1.概述 作用:用于维护资源计划,资源使用组和资源计划指令;包dbms_resource_manager_privs用于维护与资源管理相关的权限. 2.包的组成 1).dbms_resource_ma ...
- C# 设计模式巩固 - 抽象工厂模式
前言 继续工厂模式高级版,抽象工厂模式.抽象工厂模式其实是从工厂方法模式拓展而来.在实际的生活中一个工厂的产品不可能是单一的,肯定是多种系列的产品. 介绍 - 抽象工厂模式 定义:(摘自百度百科~ ...
- python 获取当前时间(关于time()时间问题的重要补充)
python 获取当前时间 我有的时候写程序要用到当前时间,我就想用python去取当前的时间,虽然不是很难,但是老是忘记,用一次丢一次,为了能够更好的记住,我今天特意写下python 当前时间这 ...
- 20165202 2017-2018-2 《Java程序设计》第8周学习总结
20165202 2017-2018-2 <Java程序设计>第8周学习总结 教材学习内容总结 Ch12 进程与线程 线程是比进程更小的单位,一个进程在其执行过程中,可以产生多个线程 Ja ...
- JUnit出错,却没有显示任何报错信息【待解答】
JUnit测试代码如下: 原因分析: JUnit测试单元里,测试函数好像不能带参数? 解决办法: 发现测试函数testBookShopDaoUpdateBookStock(int isbn)里的参数i ...
- vue.js 源代码学习笔记 ----- instance event
/* @flow */ import { updateListeners } from '../vdom/helpers/index' import { toArray, tip, hyphenate ...
- c# excel转换为DataTable
System.Data.DataTable GetDataFromExcelByCom(bool hasTitle, string fileName) { //OpenFileDialog openF ...
- for循环打印等腰三角形、直角三角形、菱形
一.等腰三角形 package s1; import java.util.Scanner; public class C31 { public static void main(String[] ar ...