八皇后问题的解决完整文档

合集下载

八皇后问题(经典算法-回溯法)

八皇后问题(经典算法-回溯法)

⼋皇后问题(经典算法-回溯法)问题描述:⼋皇后问题(eight queens problem)是⼗九世纪著名的数学家⾼斯于1850年提出的。

问题是:在8×8的棋盘上摆放⼋个皇后,使其不能互相攻击。

即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上。

可以把⼋皇后问题扩展到n皇后问题,即在n×n的棋盘上摆放n个皇后,使任意两个皇后都不能互相攻击。

思路:使⽤回溯法依次假设皇后的位置,当第⼀个皇后确定后,寻找下⼀⾏的皇后位置,当满⾜左上、右上和正上⽅向⽆皇后,即矩阵中对应位置都为0,则可以确定皇后位置,依次判断下⼀⾏的皇后位置。

当到达第8⾏时,说明⼋个皇后安置完毕。

代码如下:#include<iostream>using namespace std;#define N 8int a[N][N];int count=0;//判断是否可放bool search(int r,int c){int i,j;//左上+正上for(i=r,j=c; i>=0 && j>=0; i--,j--){if(a[i][j] || a[i][c]){return false;}}//右上for(i=r,j=c; i>=0 && j<N; i--,j++){if(a[i][j]){return false;}}return true;}//输出void print(){for(int i=0;i<N;i++){for(int j=0;j<N;j++){cout<<a[i][j]<<" ";}cout<<endl;}}//回溯法查找适合的放法void queen(int r){if(r == 8){count++;cout<<"第"<<count<<"种放法\n";print();cout<<endl;return;}int i;for(i=0; i<N; i++){if(search(r,i)){a[r][i] = 1;queen(r+1);a[r][i] = 0;}}}//⼊⼝int main(){queen(0);cout<<"⼀共有"<<count<<"放法\n"; return 0;}。

八皇后实验报告

八皇后实验报告

八皇后实验报告八皇后实验报告引言:八皇后问题是一个经典的数学问题,它要求在一个8x8的国际象棋棋盘上放置8个皇后,使得任意两个皇后都不会互相攻击。

这个问题看似简单,但实际上却充满了挑战。

在本次实验中,我们将探索八皇后问题的解法,并通过编写算法来解决这个问题。

一、问题背景:八皇后问题最早由数学家马克斯·贝瑟尔于1848年提出,它是一道经典的递归问题。

在国际象棋中,皇后可以在同一行、同一列或同一对角线上进行攻击,因此我们需要找到一种方法,使得8个皇后彼此之间不会相互攻击。

二、解决方法:为了解决八皇后问题,我们可以使用回溯法。

回溯法是一种穷举搜索的方法,它通过逐步尝试所有可能的解决方案,直到找到符合要求的解。

具体步骤如下:1. 初始化一个8x8的棋盘,并将所有格子标记为无皇后。

2. 从第一行开始,依次尝试在每一列放置一个皇后。

3. 在每一列中,检查当前位置是否符合要求,即与已放置的皇后不在同一行、同一列或同一对角线上。

4. 如果当前位置符合要求,将皇后放置在该位置,并进入下一行。

5. 如果当前位置不符合要求,尝试在下一列放置皇后。

6. 重复步骤3-5,直到找到一个解或者所有可能的位置都已尝试过。

7. 如果找到一个解,将其输出;否则,回溯到上一行,继续尝试下一列的位置。

三、编写算法:基于上述步骤,我们可以编写一个递归函数来解决八皇后问题。

伪代码如下所示:```function solveQueens(board, row):if row == 8:print(board) # 打印解returnfor col in range(8):if isSafe(board, row, col):board[row][col] = 1solveQueens(board, row + 1)board[row][col] = 0function isSafe(board, row, col):for i in range(row):if board[i][col] == 1:return Falseif col - (row - i) >= 0 and board[i][col - (row - i)] == 1:return Falseif col + (row - i) < 8 and board[i][col + (row - i)] == 1:return Falsereturn Trueboard = [[0]*8 for _ in range(8)]solveQueens(board, 0)```四、实验结果:通过运行上述算法,我们得到了八皇后问题的所有解。

八皇后问题有多少解

八皇后问题有多少解

八皇后问题有多少解八皇后问题有92解。

皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。

如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。

对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,‘即a=b1b2…b8,其中bi为相应摆法中第i行皇后所处的列数。

已经知道8皇后问题一共有92组解(即92个不同的皇后串)。

给出一个数b,要求输出第b个串。

串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。

//输入数据//第1行是测试数据的组数n,后面跟着n行输入。

每组测试数据占1行,包括一个正整数b(1 <= b <= 92)//输出要求//n行,每行输出对应一个输入。

输出应是一个正整数,是对应于b 的皇后串//输入样例//2//1//92//输出样例//15863724//84136275解题思路一因为要求出92种不同摆放方法中的任意一种,所以我们不妨把92种不同的摆放方法一次性求出来,存放在一个数组里。

为求解这道题我们需要有一个矩阵仿真棋盘,每次试放一个棋子时只能放在尚未被控制的格子上,一旦放置了一个新棋子,就在它所能控制的所有位置上设置标记,如此下去把八个棋子放好。

当完成一种摆放时,就要尝试下一种。

若要按照字典序将可行的摆放方法记录下来,就要按照一定的顺序进行尝试。

也就是将第一个棋子按照从小到大的顺序尝试;对于第一个棋子的每一个位置,将第二个棋子从可行的位置从小到大的顺序尝试;在第一第二个棋子固定的情况下,将第三个棋子从可行的位置从小到大的顺序尝试;依次类推。

首先,我们有一个8*8的矩阵仿真棋盘标识当前已经摆放好的棋子所控制的区域。

用一个有92行每行8个元素的二维数组记录可行的摆放方法。

用一个递归程序来实现尝试摆放的过程。

基本思想是假设我们将第一个棋子摆好,并设置了它所控制的区域,则这个问题变成了一个7皇后问题,用与8皇后同样的方法可以获得问题的解。

八皇后问题的解决方案

八皇后问题的解决方案

算法总结
3
解决八皇后问题常用算法
3.1
枚举法解决八皇后问题
3.2
非递归回溯法解决八皇后问题
3.3
递归回溯法解决八皇后问题
3.0
八皇后问题约束条件
a( i ) 1 2 3 4 5 6 7 8 a( 1) 2 0 -1 3 -2 4 -3 5 -4 6 -5 7 -6 8 -7 9
a( 2 ) a( 3 ) a( 4) a( 5 ) a( 6) a( 7 ) a( 8)
9 3 10 2 11 1 12 0 13 -1 14 -2
9 5 10 4 11 3 12 2 13 1 14 0 15 -1
9 7 10 6 11 5 12 4 13 3 14 2 15 1 16 0
3.0
八皇后问题约束条件
a( i ) =j 第i行j列放置皇后
判断不同列 a(i)≠a(j) 判断不同对角线 i-a(i)≠j-a(j) 判断不同反对角线 i+a(i)≠j+a(j)
取下一个………………
取下一个q (1)
用语言编程
For q1 = 1 To 8 For q2 = 1 To 8 For q3 = 1 To 8 For q4 = 1 To 8 For q5 = 1 To 8 For q6 = 1 To 8 For q7 = 1 To 8 For q8 = 1 To 8 q(q1) = q1 : q(q2) = q2 : q(q3) = q3 : q(q4) = q4 q(q5) = q5 : q(q6) = q6 : q(q7) = q7 : q(q8) = q8 If putdown(q)=1 Then printstr(q) Next q8 Next q7 Next q6 Next q5 Next q4 Next q3 Next q2 Next q1

皇后问题详细的解法

皇后问题详细的解法

for(a[7]=1;a[7]<=8;a[7]++} )
for(a[8]=1;a[8]<=8;a[8]++){
if (check(a,8)=0) continue;
else
for(i=1;i<=8;i++)print(a[i]);
}
10
}
1 回溯法
有“通用的解题法”之称。 回溯法的基本做法是搜索,或是一种组织得井井有条
枚举得有个顺序,否则 轻则有漏的、重复的; 重则无法循环表示。
6
1.按什么顺序去查找所有的解 a.盲目的枚举算法
void main() {
int x[100]; for (x[1]=1;x[1]<=10;x[1]++) for (x[2]=1;x[2]<=10;x[2]++)
for (x[3]=1;x[3]<=10;x[3]++) for (x[4]=1;x[4]<=10;x[4]++) for (x[5]=1;x[5]<=10;x[5]++) for (x[6]=1;x[6]<=10;x[6]++) for (x[7]=1;x[7]<=10;x[7]++) for (x[8]=1;x[8]<=10;x[8]++) if (check(x)==0) { printf(x); }
}
该如何解决冲突的问题呢?
1.行;我们是按照行枚举的,保证了一行一个皇后; 2.列:判断是否存在x[i]=x[j] 3.对角线:主对角线的i-j与从对角线的i+j存在特殊关系,如 图:

八皇后问题(N皇后问题)

八皇后问题(N皇后问题)

⼋皇后问题(N皇后问题)⼋皇后问题,是⼀个古⽼⽽著名的问题,是回溯算法的典型案例。

该问题是国际西洋棋棋⼿马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放⼋个皇后,使其不能互相攻击,即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上,问有多少种摆法。

⾸先来看看这张模拟⼋皇后的图。

这张图说明皇后具有横轴、竖轴以及两个斜轴⽅向的杀伤⼒,也就是像⽶字形⼀样;为了减少判断,我们按照⼀个⽅向往另⼀个⽅向排列,中间不能跳⾏,这样我们就可以只判断已经有皇后的位置,还没有皇后的就可以偷懒不⽤判断了。

我的⽅案是:1.从最下⾯开始排列,然后往上添加,从左往右排列,这样就只需要判断⽐⾃⼰Y坐标低的具有杀伤能⼒的位置有没有皇后就OK ⽅法是把⾃⼰假定要放置皇后的位置的X和Y轴都依据判断特性进⾏处理;例如,左斜线X和Y轴都减1;中间的只需要把Y 轴减1;右边的和左边的相反,X轴加1,Y轴减1;注意处理边界问题。

2.为了找到合适的位置我们需要在查找失败的时候具备回溯的能⼒,就需要退回到前⼀⾏(Y=Y-1,注意XY是否到边界),直⾄能回溯或者全部判断完毕,每次回溯的时候记得X轴要从头开始 3.通过⼀个数据结构记录正在查找的⽅案,通过另⼀个数据结构记录已经找到的⽅案,当然也可以⽤⼀个变量记录⽅案个数下⾯这张⿊⾊背景是其中⼀个⽅案的截图,第⼀⾏代表皇后的坐标xy;后⾯的是棋盘,这⾥输出竖轴是x,横轴是y,从上到下,从左到右,其中*是边界,空格是空区,#是皇后。

#include <iostream>#include <cstring>#include "DTString.h"#include "LinkList.h" // 这⾥使⽤链表存储皇后的位置using namespace std;using namespace DTLib;template <int SIZE> // N皇后问题,SIZE表⽰皇后个数或者棋盘⼤⼩class QueenSolution : public Object{protected:enum { N = SIZE + 2 }; // N表⽰棋盘⼤⼩,为了边界识别,棋盘四周都要加⼀格struct Pos : public Object // ⽅位结构体{Pos(int px = 0, int py = 0) : x(px), y(py) { }int x;int y;};int m_chessboard[N][N]; // 棋盘,0表⽰空位,1表⽰皇后,2表⽰边界Pos m_direction[3]; // 共3个⽅向;⽅向-1、-1表⽰左斜线;0、-1表⽰下⽅;1、-1表⽰右斜线;⾸先从最下⽅开始,所以只需考虑下⾯的⾏。

八皇后问题

八皇后问题

八皇后问题1、问题描述八皇后问题是一个古老而著名的问题,该问题是由十九世纪著名的数学家高斯1850年提出的。

在国际象棋中,皇后是最有权利的一个棋子,只要别的棋子在它的同一行或同一列或同一斜线(正斜线或反斜线)上时,它就能把对方棋子吃掉。

所以高斯提出了一个问题:在8*8格的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后都不能处于同一列、同一行、同一条斜线上面,问共有多少种解法。

2、设计思路1)解决行、列、斜线的冲突行:当第i行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,还要把以i为下标的位置标记为已占领列:规定每一列放置一个皇后,保证不会造成列上的冲突对角线:对角线有正对角线和反对角线两个方向。

当第i个皇后占领了第j列后,要同时把以(i+j)、(i-j)为下标的位置标记为已占领2)数据结构的实现数组a[i]:a[i]表示第i个皇后放置的列(1<=i<=8)对角线数组:b[j](正对角线),c[j](反对角线),根据程序决定正反对角线是否放入皇后3、数据结构设计int Count=0;/*记录解的序号*/int Site[QUEENS]; /*记录皇后放置在各行的位置*/void Queen(int n);/*递归求解函数*/{ int i;if(n==QUEENS){ Output();return;}}void Output();/*输出一个解法*/{ int i;for(i=0;i<QUEENS;i++)/*依次输出各行上皇后的位置*/}int IsValid(int n); /*判断第n个皇后放后,是否有冲突*/ { int i;for(i=0;i<n;i++) /*将第n个皇后和前面n-1个皇后比较*/ { if(Site[i]==Site[n])/*两个皇后在同一列上,返回0*/return 0;if(abs(Site[i]-Site[n])==(n-i))/*两个皇后在同一对角线上,返回0*/return 0;}return 1; /*没有冲突,返回1*/}4、功能函数设计1)求解函数void Queen(int n):递归放置第n个皇后,判断第n个皇后放上去之后,是否无冲突。

八皇后问题详细的解法

八皇后问题详细的解法

若无法放下皇后则回到上一行; 即回溯
当n行的皇后都已确定后;我们就 找到了一种方案
check2 int a ;int n
queen21例1 b加约束的枚举算法{//i多nt次i; 被调用;只是一重循环
{int a9; for a1=1;a1<=8;a1++ for a2=1;a2<=8;a2++
fori=1;i<=n-1;i++ if absai-an==absi-n or ai==an
}}}}}}}
此算法可读性很好;体 现了“回溯”&但它只 能解决八皇后问题;而 不能解决任意的n皇后 问题&
18
2 回溯法应用-算法说明
八皇后问题中的核心代码: 遍历过程函数; check函数&
解决此类问题的核心内容: 解空间树的搜索算法; 估值/判断函数:判断哪些状态适合继续扩展;或者作为 答案状态&
按什么顺序去搜? 目标是没有漏网之鱼;尽量速度快&
5
2 问题设计盲目的枚举算法
a 盲目的枚举算法
通过8重循环模拟搜索空间中的88个状态;
按枚举思想;以DFS的方式;从第1个皇后在第1列开始搜 索;枚举出所有的“解状态”:
从中找出满足约束条件的“答案状态”&
约束条件?
枚举得有个顺序;否则轻 则有漏的、重复的;重 则无法循环表示&
9
queen1 盲目的枚举算法
{ int a9;
用a1~a8存储x1~x8
for a1=1;a1<=8;a1++
for a2=1;a2<=8;a2++
for a3=1;a3<=8;a3++

八皇后所有可能的方案

八皇后所有可能的方案
▕ █ ★ █ █▏
▔▔▔▔▔▔▔▔
第 7种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█★█ █ █ ▏
▕ █ █★█ █▏
▕█ █ █ ★ ▏
▕ █ ★ █ █▏
▕★ █ █ █ ▏
▕ █ █ █ ★▏
▕█ █ █★█ ▏
▕ █ █ ★ █▏
▔▔▔▔▔▔▔▔
第14种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ ★ █ █ ▏
▕ █ █★█ █▏
▕█★█ █ █ ▏
▕ █ █ █ ★▏
▕★ █ █ █ ▏
▕ █ █ █★█▏
▕█ █★█ █ ▏
▕ █ █★█ █▏
▔▔▔▔▔▔▔▔
第33种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ █★█ █ ▏
▕ ★ █ █ █▏
▕█ █ █ ★ ▏
▕ █★█ █ █▏
▕█ █ █★█ ▏
▕ █ █ █ ★▏
▕ █ █★█ █▏
▔▔▔▔▔▔▔▔
第20种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ ★ █ █ ▏
▕ █ █ ★ █▏
▕█★█ █ █ ▏
▕ █ █ █★█▏
▕█ █ ★ █ ▏
▕★█ █ █ █▏
▕█ █ █ █★▏
▕ █ █ ★ █▏
▔▔▔▔▔▔▔▔
第27种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ ★ █ █ ▏
▕ █ █ █★█▏
▕█★█ █ █ ▏
▕ █ █ █ ★▏
▕█ █ █★█ ▏
▕ █ ★ █ █▏

八皇后 实验报告

八皇后 实验报告

八皇后实验报告八皇后实验报告导言:八皇后问题是一个经典的数学问题,最早由西班牙的数学家马克斯·贝恩在1848年提出。

问题的目标是在一个8×8的棋盘上,放置8个皇后,使得它们互相之间无法攻击到对方。

本次实验旨在通过编程的方式求解八皇后问题,并分析解的个数和解的特点。

一、问题描述八皇后问题可以简化为在一个8×8的棋盘上放置8个皇后,使得任意两个皇后都不在同一行、同一列或同一斜线上。

这意味着每一行和每一列最多只能有一个皇后。

二、算法设计为了求解八皇后问题,我们采用了回溯算法。

回溯算法是一种通过逐步试错的方式来寻找问题解的方法。

具体的算法步骤如下:1. 从棋盘的第一行开始,依次尝试在每一列放置一个皇后。

2. 在放置一个皇后后,检查是否满足任意两个皇后都不在同一行、同一列或同一斜线上的条件。

3. 如果满足条件,则继续到下一行放置皇后;如果不满足条件,则回溯到上一行重新选择位置。

4. 当最后一行的皇后放置完毕后,即找到了一个解,记录下来。

5. 继续回溯,寻找下一个解,直到所有解都找到为止。

三、实验结果通过编程实现了八皇后问题的求解算法,并运行了多组实验。

实验结果如下:1. 解的个数在8×8的棋盘上,共有92个不同的解。

每个解都代表了一种放置皇后的方式,使得它们互不攻击到对方。

2. 解的特点(1) 对称性:在所有的解中,有一半解是对称的。

即如果一个解是对称的,那么它的镜像解也是一个合法解。

(2) 旋转性:每个解可以通过旋转得到其他的合法解。

例如,一个解可以通过将整个棋盘顺时针旋转90度得到另一个解。

(3) 反射性:每个解可以通过水平或垂直翻转得到其他的合法解。

例如,一个解可以通过将整个棋盘水平翻转得到另一个解。

(4) 解的数量:解的数量随着棋盘大小的增加而急剧增加。

在8×8的棋盘上有92个解,而在9×9的棋盘上有352个解。

四、讨论与总结八皇后问题是一个非常经典的数学问题,通过本次实验我们可以得出以下结论:1. 回溯算法是求解八皇后问题的有效方法,可以找到所有的解。

八皇后问题详细的解法

八皇后问题详细的解法
八皇后问题
1
1八皇后问题背景 2盲目的枚举算法 3加约束的枚举算法 4回溯法及基本思想 5 回溯法应用 6八皇后问题的递归回溯算法 7八皇后问题的非递归回溯算法
2
【背景】 八皇后问题是一个以国际象棋为背
景的问题: 如何能够在 8×8 的国际象棋棋盘上
放置八个皇后,使得任何一个皇后都 无法直接吃掉其他的皇后?为了达到 此目的,任两个皇后都不能处于同一 条横行、纵行或斜线上。
}
}
23
20
2 回溯法应用-算法框架-递归算法框架
int a[n]; Queens(int k) { if (k>n) 即表示最后一个皇后摆放完毕,输出结果;
else for(i=下界 ; i<=上界; i++) //枚举K个皇后所有可能的路径 {依次从列顶端开始搜索,一直到列底端,直到找到合适位置,如
果未找到,自动返回上层递归
的,能避免不必要搜索的穷举式搜索法。这种方法适 用于解一些组合数相当大的问题。 回溯法在问题的解空间树中,按深度优先策略,从根 结点出发搜索解空间树。算法搜索至解空间树的任意 一点时,先判断该结点是否包含问题的解。如果肯定 不包含,则跳过对该结点为根的子树的搜索,逐层向 其祖先结点回溯;否则,进入该子树,继续按深度优 先策略搜索。
for(a[8]=1;a[8]<=8;a[8]++) 此算法可读性很好,
{if (check(a,8)==0)continue; 体现了“回溯”。但
else for(i=1;i<=8;i++) 它只能解决八皇后问
print(a[i]); }
题,而不能解决任意
}}}}}}}

八皇后问题

八皇后问题

八皇后问题一、问题描述八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。

该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

二、问题分析在一个8×8的棋盘里放置8个皇后,要求每个皇后两两之间不相"冲"(在每一横列竖列斜列只有一个皇后)。

1、冲突。

包括行、列、两条对角线:(1)列:规定每一列放一个皇后,不会造成列上的冲突;(2)行:当第I行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以I为下标的标记置为被占领状态;(3)对角线:对角线有两个方向。

在同一对角线上的所有点(设下标为(i,j)),要么(i+j)是常数,要么(i-j)是常数。

因此,当第I个皇后占领了第J列后,要同时把以(i+j)、(i-j)为下标的标记置为被占领状态。

三、基本解决思路八皇后问题主要靠回溯的方法实现, 与迷宫的实现相似, 但又困难了一些. 如迷宫的路径不因为上一步而改变, 八皇后的每一步都受约束于以前的步数, 并且, 迷宫只要找出一条路径就行,但八皇后则有很多的解法.基本思想是从n列开始摆放第n个皇后(因为这样便可以符合每一竖列一个皇后的要求),先测试当前位置(n,m)是否等于0(未被占领):如果是,摆放第n个皇后,并宣布占领(记得要横列竖列斜列一起来哦),接着进行递归;如果不是,测试下一个位置(n,m+1),但是如果当n<=8,m=8时,却发现此时已经无法摆放时,便要进行回溯。

1.回溯算法的实现(1)为解决这个问题,我们把棋盘的横坐标定为i,纵坐标定为j,i和j的取值范围是从1到8。

当某个皇后占了位置(i,j)时,在这个位置的垂直方向、水平方向和斜线方向都不能再放其它皇后了。

用语句实现,可定义如下三个整型数组:a[8],b[15],c[24]。

其中:a[j-1]=1 第j列上无皇后a[j-1]=0 第j列上有皇后b[i+j-2]=1 (i,j)的对角线(左上至右下)无皇后b[i+j-2]=0 (i,j)的对角线(左上至右下)有皇后c[i-j+7]=1 (i,j)的对角线(右上至左下)无皇后c[i-j+7]=0 (i,j)的对角线(右上至左下)有皇后(2)为第i个皇后选择位置的算法如下:for(j=1;j<=8;j++) /*第i个皇后在第j行*/if ((i,j)位置为空))/*即相应的三个数组的对应元素值为1*/{占用位置(i,j)/*置相应的三个数组对应的元素值为0*/if (i<8)为i+1个皇后选择合适的位置;else 输出一个解}2.图形存取在Turbo C语言中,图形的存取可用如下标准函数实现:size=imagesize(x1,y1,x2,y2) ;返回存储区域所需字节数。

1213:八皇后问题

1213:八皇后问题

1213:⼋皇后问题⾸先可以试图去简化问题,将问题转化为为每⼀列确定⼀个有效的⾏号。

因为同⼀列只能有⼀个皇后,并且需要在⼋列中确定⼋个皇后,即每⼀列都必定有且只有⼀个皇后。

经过简化后,显然,通过⼀个⼀维数组即可以确定⼀组有效解。

关于check:不为同⼀⾏或同⼀列的判定⽐较简单(这⾥省略)(i1,j1)与(i2,j2)在同⼀条斜线上的判定:i1-i2==j1-j2 || i1-i2==j2-j1问题经过这样⼀次抽丝剥茧后,剩余的思路⼤致就是深度搜索、临界输出。

特别重复:a[j]表⽰第j列的皇后所在的⾏数1 #include<iostream>2 #include<cstdio>3using namespace std;45const int N=10;6int ans,a[N];7void print(){8 printf("No. %d\n",++ans);9for(int i=1;i<=8;i++){10for(int j=1;j<=8;j++)11if(a[j]==i)printf("1 ");12else printf("0 ");13 printf("\n");14 }15 }16bool check(int x,int d){17for(int i=1;i<d;i++){18if(a[i]==x||x-a[i]==d-i||x-a[i]==i-d)19return0;20 }21return1;22 }23void solve(int d){24if(d==9){25 print();26return;27 }28for(int i=1;i<=8;i++){29if(check(i,d)){30 a[d]=i;31 solve(d+1);32 }33 }34 }35int main(){36 solve(1);37return0;38 }。

八皇后问题

八皇后问题

八皇后问题八皇后问题是一个国际象棋以为背景的问题:如何能够在 8&s;8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法挺直吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。

我们定义这样的一个一维数组,数组的下标表示第i行,数组的值表示第i列,数组大小为8,把数组初始化为从0到7的八个不同值。

相当与对01234567做全罗列,这样所以的数字自然不再同一行,同一列,即数组下标的值各不相同,数组的值各不相同,且都是取从0到7的不同值。

现在要解决的就是对角线的问题,假如两个元素处在同一对角线,则有数组下标之差的肯定值等于数组元素值之差的肯定值。

即 abs(i-j) == abs(array[i] - array[j])。

代码如下: ilude stdio.h include stdlib.h include math.h ic int total = 0;const int QueensNum = 8;vo swap(int * a, int * b){ if(a == b) return;*a = *a + *b; *b = *a - *b; *a = *a - *b;}int check(int array[], int n){ int i, j; for(i=0;i n;++i) { for(j=i+1;j n;++j)if(abs(i-j) == abs(array[i] - array[j])) return 0; } return 1;}void peutation(int array[], int ind, int n){ int i; if (index == n) { if(check(array, n)) { for(i = 0; i n; ++i){ printf(\"(%d,%d) \",i,array[i]); } printf(\"n\"); ++total; } } ee { for (i = index; i n; i++) { swap( array[index], array[i]); permutation(array, index + 1, n); swap( array[index],array[i]); } }}void QueensInit(int array[],int n){ int i; for(i = 0; i n; ++i) { array[i] = i; }}int main(int argc, char**argv){ int array[QueensNum]; QueensInit(array, QueensNum); permutation(array, 0 ,QueensNum); printf(\"total solution number is %dn\", total);第1页共1页。

算法——八皇后问题(eightqueenpuzzle)之回溯法求解

算法——八皇后问题(eightqueenpuzzle)之回溯法求解

算法——⼋皇后问题(eightqueenpuzzle)之回溯法求解⼋皇后谜题是经典的⼀个问题,其解法⼀共有92种!其定义:1. ⾸先定义⼀个8*8的棋盘2. 我们有⼋个皇后在⼿⾥,⽬的是把⼋个都放在棋盘中3. 位于皇后的⽔平和垂直⽅向的棋格不能有其他皇后4. 位于皇后的斜对⾓线上的棋格不能有其他皇后5. 解出能将⼋个皇后都放在棋盘中的摆法这个问题通常使⽤两种⽅法来求解:1. 穷举法2. 回溯法(递归)本⽂章通过回溯法来求解,回溯法对⽐穷举法⾼效许多,让我们学习如何实现吧!实现思想:1. 我们先在棋盘的第0⾏第1个棋格放下第⼀个皇后2. 下⼀⾏寻找⼀个不冲突的棋格放下下⼀个皇后3. 循环第2步4. 如果到某⼀⾏全部8个格⼦都⽆法放下皇后,回溯到前⼀⾏,继续寻找下⼀个不冲突的棋格5. 把8个皇后都放在棋盘之后,输出或存储摆法,结束实现(Java)算法:定义棋盘我们通过⼀个⼆维整型数组表⽰⼀个棋盘数组内为1是放下了的皇后,0则是空⽩的棋格我们下下⾯定义⼀个⽅法:通过检查棋格是否为1来知道是不是有皇后1// 定义⼀个棋盘2static int chessboard[][] = new int[8][8];检查冲突这个⽅法⽤来检查冲突:在⽔平垂直⽅向、斜⾓上的棋格有⽆其他皇后,传⼊的(x,y)是需要检查的棋格,如检查棋格(1,0)即棋盘的第2⾏第1个,是否能放下皇后。

1// 检查是否符合规则2private static boolean checked(int x,int y){3for(int i = 0;i<y;i++){4// 检查⽔平垂直⽅向5if(chessboard[x][i]==1)return false;6// 检测左斜⾓7if((x-y+i>=0)&&chessboard[x-y+i][i]==1)return false;8// 检查右斜⾓9if((x+y-i<=7)&&chessboard[x+y-i][i]==1)return false;10 }11return true;12 }放下皇后我们在每⼀⾏都执⾏以下步骤,通过从第1个棋格到第8个遍历寻找可以放下皇后的棋格如果放下了皇后,我们就可以继续放下下⼀个了,将⾏数+1,我们递归调⽤这个⽅法1public static boolean solve(int y){2// 将⼀⾏的8种情况都扫描⼀次3for(int i = 0;i<8;i++){4// 每次检测前都将当前⾏清空,避免脏数据5for(int k = 0;k<8;k++)chessboard[k][y]=0;6if(checked(i, y)){7 chessboard[i][y] = 1;8// 当前⼀⾏已经获得解法,进⼊下⼀⾏9 solve(y+1);10 }11 }12return false;13 }算法边界当我们放下了所有8个皇后后,需要⼀个终⽌条件,我们在⾏数y=8时,结束算法同时你可以输出⼀个棋盘摆法了!恭喜你已经把这个经典问题解决了!1// 当y=8时,已经找到⼀种解决⽅法2if(y == 8){3return true;4 }以下是完整的算法1public class EightQueen{2// 定义⼀个棋盘3static int chessboard[][] = new int[8][8];4// 计数器5static int count = 0;67// 解题⽅法8public static boolean solve(int y){9// 当y=8时,已经找到⼀种解决⽅法,计数器加⼀并输⼊摆法10if(y == 8){11 System.out.println("solved!");12 show();13 count++;14return true;15 }16// 将⼀⾏的8种情况都扫描⼀次17for(int i = 0;i<8;i++){18// 每次检测前都将当前⾏清空,避免脏数据19for(int k = 0;k<8;k++)chessboard[k][y]=0;20if(checked(i, y)){21 chessboard[i][y] = 1;22// 当前⼀⾏已经获得解法,进⼊下⼀⾏23 solve(y+1);24 }25 }26return false;27 }28// 检查是否符合规则29private static boolean checked(int x,int y){30for(int i = 0;i<y;i++){31// 检查垂直⽅向32if(chessboard[x][i]==1)return false;33// 检测左斜⾓34if((x-y+i>=0)&&chessboard[x-y+i][i]==1)return false;35// 检查右斜⾓36if((x+y-i<=7)&&chessboard[x+y-i][i]==1)return false;37 }38return true;39 }40// 输出棋盘摆法41public static void show(){42for(int i = 0;i<8;i++){43for(int j = 0;j<8;j++){44 System.out.print(chessboard[j][i]+" ");45 }46 System.out.println("");47 }48 }49 }在执⾏这个算法后:have 92 ways to sovle it!我们获得了92种棋盘摆法!。

国际象棋中的八皇后问题解决实验报告

国际象棋中的八皇后问题解决实验报告

八皇后一、作业题目:在国际象棋的棋盘上摆上八个皇后,使得任何两个皇后不在一行,不在一列,同时也不在一条斜线上。

要求找出所有的解。

二、作业目的:(1)训练C语言编程能力和数据结构中一些方法的运用。

(2)体会数据结构中的方法对简化编程的好处。

三、作业要求:在国际象棋的棋盘上摆上八个皇后,使得任何两个皇后不在一行,不在一列,同时也不在一条斜线上。

要求找出所有可行的方法,并输出所有方法的数目和每种方法如何排列。

四、算法思想:先将所有的点全部置为有可能有皇后,选择第一行的一个点为起点后,进行修剪,当某个点所在的行列斜边都有可能皇后时,则该点有皇后,同时将该点所在的直线斜线上除此点外的所有点都标记为不可能有皇后。

用递归法遍历下面的行。

即前面行的皇后确定后看后面行所有的可能情况。

当递归依次跳出,跳到第一次调用的的子函数时,则该起点对应的方法都找完了。

找出该起点所对应的所有方法后,起点在第一行向后移,再递归遍历。

当遍历完同一行八个起点后,就可以得出所有方法。

用一个子函数输出结果,其中有皇后的地方用“Q”表示,没有的用“.”表示。

五、数据结构:用数组存储六、程序:#include <stdio.h>#include <stdlib.h>#define N 8int column[N+1]; // 同栏是否有皇后,1表示有int rup[2*N+1]; // 右上至左下是否有皇后int lup[2*N+1]; // 左上至右下是否有皇后int queen[N+1] = {0};int num; // 解答编号void backtrack(int i); // 递归求解int main(void) {int i;num = 0;for(i = 1; i <= N; i++)column[i] = 1;for(i = 1; i <= 2*N; i++)rup[i] = lup[i] = 1;backtrack(1);return 0;}void showAnswer() {int x, y;printf("\n解答%d\n", ++num);for(y = 1; y <= N; y++) {for(x = 1; x <= N; x++) {if(queen[y] == x) {printf(" Q");}else {printf(" .");}}printf("\n");}}void backtrack(int i) {int j;if(i > N) {showAnswer();}else {for(j = 1; j <= N; j++) {if(column[j] == 1 &&rup[i+j] == 1 && lup[i-j+N] == 1) { queen[i] = j;// 设定为占用column[j] = rup[i+j] = lup[i-j+N] = 0;backtrack(i+1);column[j] = rup[i+j] = lup[i-j+N] = 1;}}}}七、运行结果:八、操作界面:九、结论:一共有92种遍历方法十、参考文献:[1]廖明宏郭福顺张岩李秀坤.数据结构与算法(第四版),高等教育出版社,2007.[2]苏小红陈惠鹏孙志刚.C语言大学实用教程(第二版),电子工业出版社,2010.。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

工学院数据结构课程设计报告设计题目:八皇后2008 年 6 月25 日设计任务书摘要:八皇后问题要求在一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击.按照国际象棋的规则,一个皇后可以攻击与之处在同一行或同一列或同一斜线上的其他任何棋子.因此,八皇后问题等于要求八个皇后中的任意两个不能被放在同一行或同一列或同一斜线上。

而本课程设计本人的目的也是通过用c++语言平台将一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击的92种结构予以实现.使用递归方法最终将其问题变得一目了然,更加易懂。

关键词:八皇后; c++; 递归法目录1. 课题综述 (1)1.1课题的来源及意义 (1)1.2面对的问题 (1)2. 需求分析 (1)2.1涉及到的知识 (2)2.2软硬件的需求 (2)2.3功能需求 (2)3. 概要设计 (2)4. 详细设计和实现 (3)4.1算法描述及详细流程图 (3)4.1.1算法描述 (3)4.1.2算法流程图 (3)5. 代码编写及详细注释 (4)6. 程序调试 (8)6.1调试过程、步骤及遇到的问题 (8)7. 运行与测试 (8)7.1运行演示 (8)总结 (10)致 (11)参考文献 (12).1. 课题综述1. 1课题的来源及意义八皇后问题是一个古老而著名的问题,该问题是十九世纪著名的数学家高斯1850年提出的。

在国际象棋中,皇后是最有权利的一个棋子;只要别的棋子在它的同一行或同一列或同一斜线(正斜线或反斜线)上时,它就能把对方棋子吃掉。

所以高斯提出了一个问题:在8*8的格的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后都不能处于同一列、同一行、或同一条斜线上面,问共有多少种解法。

到了现代,随着计算机技术的飞速发展,这一古老而有趣的数学游戏问题也自然而然的被搬到了计算机上。

运用所学计算机知识来试着解决这个问题是个锻炼和提高我自己编程能力和独立解决问题能力的好机会,可以使我增强信心,为我以后的编程开个好头,故我选择了这个有趣的课题。

1. 2 面对的问题1)解决冲突问题:这个问题包括了行,列,两条对角线;列:规定每一列放一个皇后,不会造成列上的冲突;行:当第I行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以I为下标的标记置为被占领状态;2)使用数据结构的知识,用递归法解决问题。

2. 需求分析2. 1 涉及到的知识本次课程设计中,用到的主要知识有:递归法的运用,for语句的灵活运用,数据结构中树知识的灵活运用、栈及数组的掌握。

2. 2 软硬件的需求1)系统要求:win98以上操作系统;2) 语言平台:tc++或vc++6.0;2. 3 功能需求当运行程序时,在屏幕上显示每一种方法八个皇后的相对位置,要用比较直观的界面显示。

3. 概要设计本课件学生是用循环递归循环来实现的,分别一一测试了每一种摆法,并把它拥有的92种变化表现出来。

在这个程序中,我的主要思路以及思想是这样的:1)解决冲突问题:这个问题包括了行,列,两条对角线;列:规定每一列放一个皇后,不会造成列上的冲突;行:当第I行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以I为下标的标记置为被占领状态;对角线:对角线有两个方向。

在这我把这两条对角线称为:主对角线和从对角线。

在同一对角线上的所有点(设下标为(i,j)),要么(i+j)是常数,要么(i-j)是常数。

因此,当第I个皇后占领了第J列后,要同时把以(i+j)、(i-j)为下标的标记置为被占领状态。

2)数据结构的实现而对于数据结构的实现,学生则是着重于:数组a[I]:a [I]表示第I个皇后放置的列;I的围:1..8;对角线数组:b[j](主对角线),c[j](从对角线),根据程序的运行,去决定主从对角线是否放入皇后;4. 详细设计和实现4. 1 算法描述及详细流程图4.1.1 算法描述A、数据初始化。

B、从n列开始摆放第n个皇后(因为这样便可以符合每一竖列一个皇后的要求),先测试当前位置(n,m)是否等于0(未被占领)。

如果是,摆放第n个皇后,并宣布占领(记得横列竖列斜列一起设置),接着进行递归;如果不是,测试下一个位置(n,m+1),但是如果当n<=8,m=8时,发现此时已无法摆放时,便要进行回溯。

从问题的某一种可能出发,搜索从这种情况能出发,继续搜索,这种不断“回溯”的寻找解的方法,称为“回溯法”。

C、使用数组实现回溯法的思想。

D、当n>8时,便打印出结果。

E、输出函数我使用printf输出,运行形式为:第m种方法为:* * * * * * * *4.1.2 算法流程图5. 代码编写及详细注释#include <conio.h>#include <math.h>#include <stdlib.h>#include <stdio.h>#include <iostream.h>#define QUEENS 8int iCount = 0; //!记录解的序号的全局变量。

int Site[QUEENS]; //!记录皇后在各行上的放置位置的全局数组。

void Queen(int n); //!递归求解的函数。

void Output();//!输出一个解。

int IsValid(int n);//!判断第n个皇后放上去之后,是否有〉冲突。

void main() /*----------------------------Main:主函数。

----------------------------*/{ system("title 叶青--递归算法八皇后问题");cout<<" "<<"八皇后的解法:"<<endl;cout<<" "<<"-------------------------------------"<<endl; Queen(0); //!从第0行开始递归试探。

getch();//!按任意键返回。

}void Queen(int n) /*-----------------Queen:递归放置第n个皇后,程序的核心!----------------*/{ int i;if(n == QUEENS) //!参数n从0开始,等于8时便试出了一个解,将它输出并回溯。

{ Output(); return; }for(i = 1 ; i <= QUEENS ; i++) //!n还没到8,在第n行的各个行上依次试探。

{ Site[n] = i; //!在该行的第i行上放置皇后。

if(IsValid(n)) //!如果放置没有冲突,就开始下一行的试探。

Queen(n + 1); }}int IsValid(int n) /*------IsValid:判断第n个皇后放上去之后,是否合法,即是否无冲突。

------*/{ int i;for(i = 0 ; i < n ; i++) //!将第n个皇后的位置依次于前面n-1个皇后的位置比较。

{ if(Site[i] == Site[n]) //!两个皇后在同一列上,返回0。

return 0;if(abs(Site[i] - Site[n]) == (n - i)) //!两个皇后在同一对角线上,返回0。

return 0; }return 1; //!没有冲突,返回1。

}void Output()/*------------Output:输出一个解,即一种没有冲突的放置方案。

------------*/{int i;printf("No.%-5d" , ++iCount); //!输出序号。

for(i = 0 ; i < QUEENS ; i++)//!依次输出各个行上的皇后的位置,即所在的列数。

printf("%d " , Site[i]);printf("\n");}6. 程序调试6. 1调试过程、步骤及遇到的问题在完整程序调试时遇到几个小问题,后经细心改正后才把调试工作做完。

例如:当用printf输出时,出现了一些错误,几经调试后,发现原来是缺少了stdio.h 这样一个头文件,添加了头文件后, 还出现了一些问题,逻辑错误导致程序死循环或不循环或循环一小部分,但是编译时却没有错误,就是没有正确的输出答案,一开始我也不知道是怎么回事,通过和同学的交流,发现是逻辑错误,经过改正后,程序终于可以运行了.7. 运行与测试7.1运行演示总结通过了19周这个星期的程序设计,我从中得到了许多的经验以及软件设计的一些新的思路;从这个八皇后问题设计以及分析中,本人从中理解到了数据结构对于计算机软件设计的重要性,它的使用,可以改变一个软件的运行周期,也可以将软件的思路从繁化简,并且都能够通过数据结构的相关引导,将本身以前编程思想进行扩充,发展;这也是在这次课程设计中我所掌握得到的。

但由于我的基本知识还不是那么扎实,也缺乏对软件设计的经验,在这过程中也出现了一些问题,如,八皇后在变成初期由于没真正体会到数据结构中“树”在里面的运用,将程序往大一时c语言的方向发展,不自觉的采用了非递归的算法,结果大大增加了程序的复杂程度。

并且也让整个程序的时间复杂度变得更大;在后来学生对数据结构的第六章进行了比较深入的研读,才发现了数据结构树的实际运用的空间是相当的大,并且,通过了重温树的回溯,以及二叉树的遍历,最终将程序进行了一次较大的改造。

并且通过思考,再将以前的数组知识加以运用才最终解决了这个问题,整个程序的算法的可看性也有了相当的改进。

课程设计随着时间的推移,也即将结束了,但这个学期数据结构的学习还是具有相当大的意义,它从一个程度上改变了我们的编程思想,如何将一个程序快速而又准备的进行编写,进行编译,都成为了我们思考的重点,也通过这一个学期的学习,我们将数据结构的思想带入到了我们以后的编程学习中去。

在这个阶段,我也明白了,好的思想,不能提留于字面上的认知,还需要的是平时多练多写一些相关的程序,并且通过修改,加入新的算法去尝试改变自己的一些编程思想。

保持更新算法的速度,这才是关键。

课程设计已经接近尾声了,但它给我的不只是程序设计上的满足,更重要的是对自己编程思想的一次更新,以及对算法的一个全新的认识!我觉得还可以考虑开发N皇后问题,在主界面中添加一个int型的变量,程序一开始要求输入一个数(确定是几皇后问题),输入后按下enter 后,输出各种解.主程序与八皇后的求解大体相同.致在这次课程设计中,我遇到了不少问题,包括程序上的和课程设计的撰写上的,同学曾给过我许多帮助,在此我表示对他们的忠心感。

相关文档
最新文档