八皇后问题说明书
- 格式:doc
- 大小:108.53 KB
- 文档页数:7
算法——⼋皇后问题(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种棋盘摆法!。
⼋皇后问题(经典算法-回溯法)问题描述:⼋皇后问题(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)```四、实验结果:通过运行上述算法,我们得到了八皇后问题的所有解。
目录摘要 (1)前言 (2)正文 (3)1.采用类C语言定义相关的数据类型 (3)2.各模块的伪码算法 (3)3.函数的调用关系图 (6)4.调试分析 (7)5.测试结果 (7)6.源程序(带注释) (10)总结 (12)参考文献 (13)致谢 (14)摘要此程序主要是实现国际象棋“八皇后”的问题。
在一个8 * 8 的棋盘上,放置八个皇后,而每个皇后之间不相互攻击。
即每行只能放一个皇后,而且每列只能放置一个皇后,每个斜行只能放一个皇后。
根据这种规定,可在8 * 8 的棋盘上实现不同的92中放法。
这个程序就根据递归算法,用简单的代码实现皇后的放法。
本次设计旨在学习各种算法,训练对基础知识和基本方法的综合运用及变通能力,增强对算法的理解能力,提高软件设计能力。
在实践中培养独立分析问题和解决问题的作风和能力。
要求熟练运用C语言、基本算法的基础知识,独立编制一个具有中等难度的、解决实际应用问题的应用程序。
通过对题意的分析与计算,用递归法回溯法及枚举法解决八皇后是比较适合的。
递归是一种比较简单的且比较古老的算法。
此外还有回溯法是递归法的升华,在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
而枚举法,更是一种基础易懂简洁的方法。
而今天所用的算法只是递归算法。
不论用什么法做这个课题,重要的就是先搞清楚哪个位置是合法的放皇后的位置,哪个不能,要先判断,后放置。
关键词:八皇后;算法设计;递归算法设计;数组前言国际象棋中,皇后是最有权利的一个棋子;只要别的棋子在它的同一行或同一列或同一斜线(正斜线或反斜线)上时,它就能把对方棋子吃掉。
所以高斯提出了一个问题:在8 * 8的格的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后都不能处于同一列、同一行、或同一条斜线上面,问共有多少种解法。
这个问题是十九世纪著名的数学家高斯1850年提出的。
高斯认为有76种方案。
1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
实验报告——八皇后问题求解(递归和非递归)学号:专业年级:姓名:一、需求分析(要实现的功能描述)1.问题描述八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。
八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。
当且仅当n=1或n≥4时问题有解。
八皇后问题最早是由国际国际象棋棋手马克斯·贝瑟尔于1848年提出。
诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。
2.实现功能八皇后问题实现了在棋盘上摆放八个皇后的功能,这八个皇后任意两个皇后都不能处于同一条横行、纵行或斜线上。
3.测试数据测试数据可以通过手工寻找三组满足需要的值,测试数组(M,N),其中M代表皇后所在的行,N代表皇后所在的列。
例如,第一组测试数据:(1,4)、(2,7)、(3,3)、(4、8)、(5,2)、(6,5)、(7,1)、(8,6);第二组测试数据(1,4)、(2,2)、(3,7)、(4,3)、(5,6)、(6,8)、(7,5)、(8,1)。
最后与编程求得的结果进行比较。
如果这三组数据在最后编程求得的结果中,说明程序的编写基本没有什么问题。
二、概要设计在进行概要设计的过程中,要清楚整个程序包含的功能模块及模块间的调用关系。
对于八皇后问题,整个程序中应该包括主函数模块,摆放皇后的函数模块,以及判断皇后的位置是否摆放正确的判断模块。
对于模块间的关系,在运行主函数的过程中会调用摆放皇后的函数模块,在摆放皇后的函数模块中,又会调用判断皇后位置是否摆放正确的判断模块。
三、详细设计抽象数据类型中定义的各种操作算法实现(用N-S图描述)对于求解八皇后问题的非递归算法,N-S图如下:对于八皇后问题求解的递归算法,N-S图如下:四、调试分析1.程序在调式过程中出现的问题及解决方法由于对于C语言编程问题掌握的并非十分熟练,因而在程序的调试过程中出现了一些问题。
八皇后问题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个皇后放上去之后,是否无冲突。
目录一需求分析 (1)1.1程序的功能: (1)1.2程序的输入输出要求: (1)二概要设计 (3)2.1程序的主要模块: (3)2.2程序涉及: (3)三详细设计 (3)3.1相关代码及算法 (4)3.1.1 定义相关的数据类型如下:....................... 错误!未定义书签。
3.1.2 主模块类C码算法: (4)3.1.3 画棋盘模块类C码算法 (5)3.1.4 画皇后模块类C码算法: (5)3.1.5 八皇后摆法模块(递归法): (6)3.1.6 初始化模块 (7)3.1.7 输出摆放好的八皇后图形(动态演示): (7)3.2相关流程图 (9)四调试分析 (12)五设计体会 (13)六附录 (13)七参考文献 (17)一需求分析1.1 程序功能:八皇后问题是一个古老而著名的问题。
该问题是十九世纪著名的数学家高斯1850年提出的。
八皇后问题要求在一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击.按照国际象棋的规则,一个皇后可以攻击与之处在同一行或同一列或同一斜线上的其他任何棋子,问有多少种不同的摆法?并找出所有的摆法。
因此,八皇后问题等于要求八个皇后中的任意两个不能被放在同一行或同一列或同一斜线上。
本程序通过对子函数void qu(int i)的调用,将八皇后的问题关键通过数据结构的思想予以了实现。
虽然题目以及演算看起来都比较复杂,繁琐,但在实际中,只要当一只皇后放入棋盘后,在横与列、斜线上没有另外一只皇后与其冲突,再对皇后的定位进行相关的判断。
即可完成。
如果在这个程序中,我们运用的是非递归的思想,那么将大量使用if等语句,并通过不断的判断,去推出答案,而且这种非递归的思想,大大的增加了程序的时间复杂度。
如果我们使用了数据结构中的算法后,那么程序的时间复杂度,以及相关的代码简化都能取得不错的改进。
这个程序,我运用到了数据结构中的栈、数组,以及树和回溯的方法。
八皇后问题(递归+非递归)Xredman posted @ 2009年6月04日 21:15 in 以前博文 , 442 阅读一.问题描述在8×8格的国际象棋棋盘上放置八个皇后,使得任意两个皇后不能互相攻击,即任何行、列或对角线(与水平轴夹角为45°或135°的斜线)上不得有两个或两个以上的皇后。
这样的一个格局称为问题的一个解。
请用递归与非递归两种方法写出求出八皇后问题的算法。
二.解题思路描述一个正确的解应当是每一列,每一行,每一条斜线上均只有一个皇后。
对于递归算法,本人才有模拟的方式进行,而且,我觉得开辟一个二维数组更显而易见。
首先,从空棋盘开始摆放,保证第m行m个皇后互不攻击,然后摆放第m+1个皇后。
当然对于第m+1个皇后可能有多种摆放方法,由此,我必须一一枚举,采用回溯策略是可行且合乎逻辑的。
而对于非递归算法,我只是借助于书本上一个递归改为非递归的框架,依次搭建而已。
在此过程中,我采用一维数组,一位对于八皇后问题,每一行不可能存在二个及二个以上的皇后,board[i]表示第i行棋盘摆放的位置为第board[i]列。
递归方法借助于系统提供的栈,而我非递归算法的实现,仅仅是自己构造一个栈而已。
递归解法#include <iostream>#include <cstdio>#include <sys/timeb.h>using namespace std;const int MAX_SIZE = 100;enum flag {blank ='X',queen = 1};char Chess[MAX_SIZE][MAX_SIZE];//棋盘图int n;//解决n皇后问题int total;//用于计摆放方式void Init(){//对棋牌进行初始化for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)Chess[i][j] = blank;total = 0;//初始时有零中摆放方式}bool Judge(int r,int c){//判断(r,c)位置是否可放置int i,j;for(i = r + 1; i < n; i++)if(Chess[i][c] == queen)return false;//说明c列上已有一皇后for(i = c + 1; i < n; i++)if(Chess[r][i] == queen)return false;//说明r行上已有一皇后for(i = r + 1, j = c + 1; (i < n) && (j < n); i++, j++)if(Chess[i][j] == queen)return false;//45度斜线上已有一皇后for(i = r + 1, j = c - 1; (i <n) && (j >= 0); i++, j--)if(Chess[i][j] == queen)return false;//135度斜线上已有一皇后return true;//排除四种情况后,说明(r,c)点可放置皇后}void Backtrack(int k,int cnt){//回溯算法主程序if(k < 0 || cnt == n)//棋牌摆放完毕 or 以摆满n后{if(cnt == n){printf("No.%d:\n",++total);for(int i = 0; i < n; i++){for(int j = 0; j < n; j++)printf(" %c ",Chess[i][j]);putchar('\n');}putchar('\n');}}else{int r = k / n, c = k % n;if(Judge(r,c)){//可放置一皇后Chess[r][c] = queen;Backtrack(k-1,cnt+1);Chess[r][c] = blank;}Backtrack(k-1,cnt);}}int main(){//此为主函数timeb t1,t2;long kk;cout<<"输入皇后个数:";while(cin>>n){Init();ftime(&t1);Backtrack(n*n-1,0);ftime(&t2);cout<<"计算"<<n<<"后问题总共可有"<<total<<"种摆法!"<<endl;kk = (t2.time-t1.time)*1000 +litm;cout<<"本次回溯耗时:"<<kk<<"毫秒"<<endl;system("PAUSE");cout<<"输入皇后个数:";}return0;}非递归解法#include <iostream>#include <sys/timeb.h>#define N 100using namespace std;int board[N];int n,sum;void init(){for(int i = 1; i <= n; i++)board[i] = 0;}void display(){int i,j;cout<<"No."<<sum<<endl;for(i = 1; i <= n; i++){for(j = 1; j <= n; j++)if(board[i] == j)cout<<"Q ";elsecout<<"X ";cout<<endl;}cout<<endl;}bool canPut(int k){for(int i = 1; i < k; i++)if((abs(k - i) == abs(board[k] - board[i])) || board[i] == board[k])return false;//1.是否在同一斜线;2.是否位于同一列return true;}void Backtrack(){board[1] = 0;int k = 1;while(k > 0){board[k]++;while((board[k] <= n) && !(canPut(k)))board[k] += 1;if(board[k] <= n)if(k == n){sum++;display();}else{k++;board[k] = 0;}elsek--;}}int main(){timeb t1,t2;long kk;cout<<"输入皇后个数:";while(cin>>n){init();sum = 0;ftime(&t1);Backtrack();ftime(&t2);cout<<"总共排列方式为:"<<sum<<endl;kk = (t2.time-t1.time)*1000 + litm; cout<<"本次回溯耗时:"<<kk<<"毫秒"<<endl;system("PAUSE");cout<<"输入皇后个数:";}return0;}。
数学与计算机学院课程设计说明书课程名称: 算法设计与分析-课程设计课程代码: 7106620题目: 八皇后问题年级/专业/班:学生姓名:学号:开始时间:2010 年12 月27 日完成时间:2011 年01月07日课程设计成绩:学习态度及平时成绩(30)技术水平与实际能力(20)创新(5)说明书撰写质量(45)总分(100)指导教师签名:年月日目录1 引言 (1)1.1问题的提出 (1)1.2任务与分析 (1)2 程序的主要功能 (1)2.1回溯功能 (1)2.2检查功能 (1)3 程序运行平台 (2)4 总体设计 (2)4.1算法设计 (2)4.2流程设计 (3)5 模块分析 (4)5.1回溯模块 (4)5.2检查模块 (5)6 系统测试 (6)7 结论 (8)8 致谢 (9)9 参考文献 (10)附录 (11)摘要本论文主要采用回溯法和递归法,求解著名的8皇后问题。
即在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,也就是任意两个皇后都不能处于同一行、同一列或同一斜线上,求可行方案的总数。
问题的提出者高斯当时认为有76种方案,后来有人用图论的方法解出92种结果。
本论文采用回溯法和递归法,在放置皇后之前,预先判断当前棋盘格子的所在行,列和主从对角线是否已存在皇后,如果存在,则右移一列进行相同判断,若右移至最后一列仍不可放,则行数加一列数回到第一列继续判断;如果不存在,则在当前格放置一个皇后,同时同行剩下的格子不再进行判断,行数加一列数回到第一列,如此递归进行,直至八个皇后全部符合要求地摆放完毕。
当判断完最后一个格子后,皇后数仍小于8,则回溯到摆放上一个皇后的格子,将上一个皇后摆放在其下一列格子上,再继续上述相同的操作,直至8个皇后摆放完毕。
此程序不仅能求解八皇后问题,还能解决相同类型的N皇后问题。
此外,代码简洁易懂,界面友好,便于操作。
关键词:n皇后,回溯,递归1 引言1.1 问题的提出问题由十九世纪著名的数学家高斯提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
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 }。
┊┊┊┊┊┊┊┊┊┊┊┊┊装┊┊┊┊┊订┊┊┊┊┊线┊┊┊┊┊┊┊┊┊┊┊┊┊一.设计目的八皇后问题是一个古老而著名的问题,该问题是十九世纪著名的数家高斯1850年提出的。
在国际象棋中,皇后是最有权利的一个棋子;只要别的棋子在它的同一行或同一列或同一斜线(正斜线或反斜线)上时,它就能把对方棋子吃掉。
所以高斯提出了一个问题:在8*8的格的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后都不能处于同一列、同一行、或同一条斜线上面,问共有多少种解法。
到了现代,随着计算机技术的飞速发展,这一古老而有趣的数学游戏问题也自然而然的被搬到了计算机上。
运用所学计算机知识来试着解决这个问题是个锻炼和提高我自己编程能力和独立解决问题能力的好机会,可以使我增强信心,为我以后的编程开个好头,故我选择了这个有趣的课题。
二. 需求分析1.涉及到的知识本次课程设计中,用到的主要知识有:递归法的运用,for语句的灵活运用,数据结构中树知识的灵活运用、栈及数组的掌握。
2. 软硬件的需求1)系统要求:win98以上操作系统;2) 语言平台:tc++或vc++6.0;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](从对角线),根据程序的运行,去决定主从对角线是否放入皇后;┊┊┊┊┊┊┊┊┊┊┊┊┊装┊┊┊┊┊订┊┊┊┊┊线┊┊┊┊┊┊┊┊┊┊┊┊┊四.详细设计和实现1. 详细流程图图12. 算法描述A、数据初始化。
B、从n列开始摆放第n个皇后(因为这样便可以符合每一竖列一个皇后的要求),先测试当前位置(n,m)是否等于0(未被占领)。
如果是,摆放第n个皇后,并宣布占领(记得姚横列竖列斜列一起设置),接着进行递归;如果不是,测试下一个位置(n,m+1),但是如果当n<=8,m=8时,发现此时已无法摆放时,便要进行回溯。
从问题的某一种可能出发,搜索从这种情况能出发,继续搜索,这种不断“回溯”的寻找解的方法,称为“回溯法”。
C、使用数组实现回溯法的思想。
D、当n>8时,便打印出结果。
E、输出函数我使用printf输出,运行形式为:第m种方法为:* * * * * * *┊┊┊┊┊┊┊┊┊┊┊┊┊装┊┊┊┊┊订┊┊┊┊┊线┊┊┊┊┊┊┊┊┊┊┊┊┊五. 代码编写及详细注释#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");}六.程序调试1.调试过程、步骤及遇到的问题在完整程序调试时遇到几个小问题,后经细心改正后才把调试工作做完。
例如:当用printf输出时,出现了一些错误,几经调试后,发现原来是缺少了stdio.h这样一个头文件,添加了头文件后, 还出现了一些问题,逻辑错误导致程序死循环或不循环或循环一小部分,但是编译时却没有错误,就是没有正确的输出答案,一开始我也不知道是怎么回事,通过和同学的交流,发现是逻辑错误,经过改正后,程序终于可以运行了.七. 运行与测试┊┊┊┊┊┊┊┊┊┊┊┊┊装┊┊┊┊┊订┊┊┊┊┊线┊┊┊┊┊┊┊┊┊┊┊┊┊1.运行演示图1图2┊┊┊┊┊┊┊┊┊┊┊┊┊装┊┊┊┊┊订┊┊┊┊┊线┊┊┊┊┊┊┊┊┊┊┊┊┊八. 总结通过了19周这个星期的程序设计,我从中得到了许多的经验以及软件设计的一些新的思路;从这个八皇后问题设计以及分析中,本人从中理解到了数据结构对于计算机软件设计的重要性,它的使用,可以改变一个软件的运行周期,也可以将软件的思路从繁化简,并且都能够通过数据结构的相关引导,将本身以前编程思想进行扩充,发展;这也是在这次课程设计中我所掌握得到的。
但由于我的基本知识还不是那么扎实,也缺乏对软件设计的经验,在这过程中也出现了一些问题,如,八皇后在变成初期由于没真正体会到数据结构中“树”在里面的运用,将程序往大一时c语言的方向发展,不自觉的采用了非递归的算法,结果大大增加了程序的复杂程度。
并且也让整个程序的时间复杂度变得更大;在后来学生对数据结构的第六章进行了比较深入的研读,才发现了数据结构树的实际运用的空间是相当的大,并且,通过了重温树的回溯,以及二叉树的遍历,最终将程序进行了一次较大的改造。
并且通过思考,再将以前的数组知识加以运用才最终解决了这个问题,整个程序的算法的可看性也有了相当的改进。
课程设计随着时间的推移,也即将结束了,但这个学期数据结构的学习还是具有相当大的意义,它从一个程度上改变了我们的编程思想,如何将一个程序快速而又准备的进行编写,进行编译,都成为了我们思考的重点,也通过这一个学期的学习,我们将数据结构的思想带入到了我们以后的编程学习中去。
在这个阶段,我也明白了,好的思想,不能提留于字面上的认知,还需要的是平时多练多写一些相关的程序,并且通过修改,加入新的算法去尝试改变自己的一些编程思想。
保持更新算法的速度,这才是关键。
课程设计已经接近尾声了,但它给我的不只是程序设计上的满足,更重要的是对自己编程思想的一次更新,以及对算法的一个全新的认识!我觉得还可以考虑开发N皇后问题,在主界面中添加一个int型的变量,程序一开始要求输入一个数(确定是几皇后问题),输入后按下enter 后,输出各种解.主程序与八皇后的求解大体相同.。