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

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

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

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

需求分析:

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

  由n*n个方块排成n行n列的正方形称为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行可能会不够显示,所以要在属性修改“高度”,使所有结果都显示出来。

时间: 2024-11-25 07:29:40

用试探回溯法解决N皇后问题的相关文章

回溯法解决八皇后问题

八皇后问题是学习回溯算法时不得不提的一个问题,用回溯算法解决该问题逻辑比较简单. 下面用java版的回溯算法来解决八皇后问题. 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 思路是按行来规定皇后,第一行放第一个皇后,第二行放第二个,然后通过遍历所有列,来判断下一个皇后能否放在该列.直到所有皇后都放完,或者放哪

回溯法解决N皇后问题

以4皇后为例,其他的N皇后问题以此类推.所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子.在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平.竖直.以及45度斜线上都不能出现皇后的棋子     1   1             1   1    

AI -- 回溯法解决四皇后问题

AI -- 回溯法解决四皇后问题 回溯法 四皇后 C语言 问题描述 在 4*4 的棋盘上无冲突的摆放 4 个皇后,无冲突是指一个皇后所在位置的水平.竖直以及斜线上不能出现其他的皇后,其他的 n 皇后问题以此类推 解决方法 按行来摆放棋子,下一行的摆放满足于与上一行的棋子没有冲突,否则就返回上一步走其他的路线,这就是所谓的回溯法 详细说明 在第一行有四种可能,选择第一个位置放上皇后 第二行原本可以有四种可能摆放,但是第一第二个已经和第一行的皇后冲突了,因此只剩下第三第四个格子了,先选择第三个格子

【基础算法】回溯法与八皇后问题

在国际象棋中,皇后是最强大的一枚棋子,可以吃掉与其在同一行.列和斜线的敌方棋子.比中国象棋里的车强几百倍,比她那没用的老公更是强的飞起(国王只能前后左右斜线走一格).上图右边高大的棋子即为皇后. 八皇后问题是这样一个问题:将八个皇后摆在一张8*8的国际象棋棋盘上,使每个皇后都无法吃掉别的皇后,一共有多少种摆法?此问题在1848年由棋手马克斯·贝瑟尔提出,岂止是有年头,简直就是有年头,82年的拉菲分分钟被秒的渣都不剩. 八皇后问题是典型的回溯法解决的问题,我们以这个问题为例介绍回溯法. 所谓回溯法

ACM:回溯法,八皇后问题,素数环

(一)八皇后问题 (1)回溯法 #include <iostream> #include <string> #define MAXN 100 using namespace std; int tot = 0, n = 8; int C[MAXN]; void search(int cur) { if(cur == n) ++tot; //递归边界,只要走到了这里,所有皇后必然不冲突 else for(int i = 0; i < n; ++i) { int ok = 1; C

回溯法求解N皇后问题

问题描述: 在n*n格的棋盘上放置彼此不受攻击的n个皇后(按照国际象棋的规则),即任意两个皇后不能处在同一行或同一列或同一斜线上. 实现: /* *回溯法,N皇后问题 *author: [email protected] */ #include <iostream> #include <vector> #include <cmath> using namespace std; struct Point{ Point(int _x, int _y): x(_x), y(_

华为机试—N皇后问题(高级题160分:两种回溯法解决 吐血整理)

一.问题描述: 在n×n格的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上. 输入: 给定棋盘的大小n (n ≤ 13) 输出: 输出有多少种放置方法. 二.解题思路: 要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行.同一列.同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇

八皇后之回溯法解决[转]

问题描述: 要在8*8的国际象棋棋盘中放8个皇后,使任意两个皇后都不能互相吃掉.规则是皇后能吃掉同一行.同一列.同一对角线的棋子.如下图即是两种方案: . 解决方案: 8*8的棋盘要摆放8个皇后,且不能同行同列同对角线,那么每行必定会有一个皇后.我们可以设一个数组a用来存放每一行皇后的位置,元素值表示第几列(如a[1]=5表示第一行的皇后处于第五个格).然后只需要求出数组a的值 问题就解决了,下面介绍三种回溯解法: 1.八个for循环.用枚举的办法,八个for循环分别枚举每一行的8个位置,但是我

【回溯法】八皇后问题(递归和非递归)

先贴代码,分递归回溯法和非递归回溯法 递归回溯法,代码如下: // test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <stdio.h> using namespace std; int a[9] = {0}; int n = 8; int count = 0; bool check