用试探回溯法解决N皇后问题

简介: 学校数据结构的课程实验之一。 数据结构:(其实只用了一个二维数组) 算法:深度优先搜索,试探回溯 需求分析:   设计一个在控制台窗口运行的“n皇后问题”解决方案生成器,要求实现以下功能:   由n*n个方块排成n行n列的正方形称为n元棋盘。

学校数据结构的课程实验之一。

数据结构:(其实只用了一个二维数组)

算法:深度优先搜索,试探回溯

需求分析:

  设计一个在控制台窗口运行的“n皇后问题”解决方案生成器,要求实现以下功能:

  由n*n个方块排成nn列的正方形称为n元棋盘。如果两个皇后位于n元棋盘上的同一行、同一列或同一对角线上,则称它们在互相攻击。现要找出使棋盘上n个皇后互不攻击的布局。

  编制程序解决上述问题,以n=6运行程序,输出结果。

算法解释:

  首先试探当前行第一个可用的位置(列、对角线没有被占领),摆放皇后之后,试探下一行的第一个可用位置;如果遇到此行没有可用位置,则返回上一行,移除上一行的皇后,试探此行的下一个可用位置,直至n个皇后全部摆放好,生成一种方案。

主函数:

 1 int main()
 2 /*Pre: The user enters a valid board size.
 3 Post: All solutions to the n-queens puzzle for the selected board size
 4 are printed.
 5 Uses: The class Queens and the recursive functionsolve from. */
 6 {
 7     int board_size;
 8     char choice = 'y';
 9     char enter;
10     while (choice == 'y')//由用户决定是否继续
11     {
12         sum = 0;
13         cout << "What is the size of the board?"<<flush;
14         cin >> board_size;
15         if(board_size < 0||board_size > max_board)
16             cout<<"The number must between 0 and "<<max_board<<endl;
17         else
18         {
19             Queens configuration(board_size);//创建size*size的对象
20             
21             cout << "there is total " << solve_from(configuration) << " configurations." << endl;//打印所有解决方案和方案个数
22         }
23         cout << endl << "Would you like to continue? [y/n]" << endl;
24         //回车符的消去
25         fflush(stdin);
26         while ((enter = cin.get()) == '\n')
27         {
28             enter = cin.get();
29         }
30         cin.putback(enter);
31         cin >> choice;//移植了计算器的代码
32     }
33     return 0;
34 }

辅助函数(计算出所有解决方案)(参考了经典教材"Data Structures and Program Design in C++" Robert L. Kruse, Alexander J. Ryba 高等教育出版社-影印版)

 1 int sum = 0;//记录解决方案个数
 2 
 3 int solve_from(Queens &configuration)//通过递归、回溯找到所有解决方案并打印
 4 /*Pre: the queens configuration represents a partially completed
 5 arrangement of nonattacking queens on a chessboard.
 6 Post: all n-queens solutions that extend the given configuration are
 7 printed. The configuration is restored to its initial state.
 8 Uses: the class Queens and the function solve_from, recursively.*/
 9 {
10     if (configuration.is_solved())//当生成一种解决方案时打印,sum自增一
11     {
12         sum++;
13         configuration.print();
14         cout <<"================" <<endl;
15     }
16     else
17         for(int col=0; col<configuration.board_size; col++)
18             if(configuration.unguarded(col))
19             {
20                 configuration.insert(col);
21                 solve_from(configuration);//recursively continue to add queens当生成一种解决方案时打印
22                 configuration.remove(col);//return the last row and the last col.试探上一层的下一种方案(无论上一次试探是成功还是失败)
23             }
24     return sum;
25 }

注:

  每次回溯其实有两种可能:“摆放满了n个皇后”或者“此行没有可放的位置”,二者都会返回上一行去试探下一种可能,只不过摆满n个皇后的情况会生成一种方案(被if截获,回到上一层循环),生成后还是回到倒数第二行再进行试探。因此一次深度优先搜索(调用一次solve_from函数)可以将所有方案全部输出。

“皇后”类的定义

 1 const int max_board = 15;//最大棋盘阶数
 2 using namespace std;
 3 
 4 class Queens
 5 {
 6 public:
 7     Queens(int size);
 8     bool is_solved() const;//判断是否完成一种方案
 9     void print() const;//打印当前方案
10     bool unguarded(int col) const;//判断某格是否可放皇后
11     void insert(int col);//摆放皇后
12     void remove(int col);//移除
13     int board_size;//dimension of board = maximum number of queens
14 private:
15     int count;//current number of queens = first unoccupied row
16     bool queen_square[max_board][max_board];//存放棋盘状态的二维数组
17 };

“皇后”类的实现(同样参考了经典教材"Data Structures and Program Design in C++" Robert L. Kruse, Alexander J. Ryba 高等教育出版社-影印版)

 1 #include <iostream>
 2 #include "Queens.h"
 3 
 4 Queens::Queens(int size)
 5 {
 6     board_size = size;
 7     count = 0;//从第一行开始计数
 8     for(int row=0; row<board_size; row++)
 9         for(int col=0; col<board_size; col++)
10             queen_square[row][col] = false;//生成size*size的空棋盘
11 }
12 
13 bool Queens::is_solved() const
14 /*whether the number of queens already placed 
15 equals board_size*/
16 {
17     bool solved = false;
18     if(count == board_size)//当board_size个皇后都摆放完毕时,生成一种方案
19         solved = true;
20     return solved;
21 }
22 
23 void Queens::print() const
24 {
25     for (int row = 0; row < board_size; row++)
26     {
27         for (int col = 0; col < board_size; col++)
28             if (queen_square[row][col] == true)
29                 cout << "* ";
30             else
31                 cout << "_ ";//逐个打印棋盘元素,有皇后打印'*',无皇后打印'_'
32         cout << endl;
33     }
34 }
35 
36 bool Queens::unguarded(int col) const
37 /*Post: Return true or false according as the square in the first
38 unoccupied row(row count) and colum col is not guarded by andy queen*/
39 {
40     int i;
41     bool ok = true;//turn false if we find a queen in column or diagonal
42     for(i=0; ok && i < count; i++)
43         ok = !queen_square[i][col];//check upper part of column同列
44     for(i=1; ok && count-i >= 0 && col-i >=0; i++)
45         ok = !queen_square[count-i][col-i];//check upper-left diagonal
46     for(i=1; ok && count-i >= 0 && col+i < board_size; i++)
47         ok = !queen_square[count-i][col+i];//chekck upper-right diagonal
48     return ok;
49 }
50 
51 void Queens::insert(int col)
52 /*Pre: The square in the first unoccupied row(row count) and column is not
53 guarded by any queen.
54 Post: A queen has been inserted into the square at row count and column col;
55 count has been incremented by 1*/
56 {
57     queen_square[count++][col] = true;//放入皇后,计数器自增一(到下一行)
58 }
59 
60 void Queens::remove(int col)
61 /*Pre: there is a queen in the square in row count-1 and column col.
62 Post: the above queen has been removed; count has been decremented by 1.*/
63 {
64     queen_square[count-1][col] = false;//移出皇后,计数器自减一(回上一行)
65     count--;
66 }
Queen.cpp

运行截图:

注:

  当输入的棋盘阶数比较大(如:8)时,命令行窗口的缓冲区默认300行可能会不够显示,所以要在属性修改“高度”,使所有结果都显示出来。

目录
相关文章
|
机器学习/深度学习 人工智能 前端开发
机器学习PAI常见问题之web ui 项目启动后页面打不开如何解决
PAI(平台为智能,Platform for Artificial Intelligence)是阿里云提供的一个全面的人工智能开发平台,旨在为开发者提供机器学习、深度学习等人工智能技术的模型训练、优化和部署服务。以下是PAI平台使用中的一些常见问题及其答案汇总,帮助用户解决在使用过程中遇到的问题。
|
虚拟化 KVM Linux
带你读《KVM实战:原理、进阶与性能调优》之二:KVM原理简介
本书兼具实战性、系统性又不乏深度的KVM虚拟化技术指南,既能让新人快速掌握KVM的基础知识,又能满足有经验的读者进阶学习的需求。本书两位作者来自于阿里云和Intel,在云计算和KVM方面有深入的研究,他们将自己的经验倾囊相授,带你全面了解KVM的各种技术细节。
|
5月前
|
人工智能 文字识别 小程序
告别手动录入!AI自动识别发票
最近有朋友向我吐槽:"每天对着几十张发票手动录入系统,眼睛都快看花了,还总担心数字打错。" 这种重复性高、容错率低的工作,确实让财务和行政人员苦不堪言。作为程序员,我深知这类场景完全可以通过技术手段优化
234 0
|
6月前
|
SQL 分布式数据库 Apache
网易游戏 x Apache Doris:湖仓一体架构演进之路
网易游戏 Apache Doris 集群超 20 个 ,总节点数百个,已对接内部 200+ 项目,日均查询量超过 1500 万,总存储数据量 PB 级别。
456 3
网易游戏 x Apache Doris:湖仓一体架构演进之路
|
12月前
|
数据库
树的分类有哪些?
本文介绍了树的多种类型,包括二叉树、二叉搜索树、完全二叉树、AVL树、红黑树、B树和B+树,并解释了每种树的特点和用途。
457 0
树的分类有哪些?
详细教程:扫码提交表单后,数据直接推送到企业微信、钉钉、飞书群聊
在草料制作的表单中,填表人扫码填写并提交数据后,这些信息可以立即通过企业微信、钉钉或飞书自动推送到相应的群聊中,实现即时共享和沟通,提升团队协作效率。
436 2
|
SQL 开发框架 .NET
你确定不学?Go标准库之 text/template
你确定不学?Go标准库之 text/template
205 2
|
Python
【Python基础】reduce函数详解
【Python基础】reduce函数详解
1338 1
|
存储 算法 Go
ZIP文件实战指南:读写操作一网打尽
ZIP文件实战指南:读写操作一网打尽
1056 0