八皇后问题文档
八皇后问题详细的解法
若无法放下皇后则回到上一行, 即回溯
当n行的皇后都已确定后,我们 就找到了一种方案
check2 (int a[ ],int n)
queen21(例) 1 b加约束的枚举算法{//i多nt次i; 被调用,只是一重循环
{int a[9]; for (a[1]=1;a[1]<=8;a[1]++) for (a[2]=1;a[2]<=8;a[2]++)
八皇后问题
1
1八皇后问题背景 2盲目的枚举算法 3加约束的枚举算法 4回溯法及基本思想 5 回溯法应用 6八皇后问题的递归回溯算法 7八皇后问题的非递归回溯算法
2
【背景】 八皇后问题是一个以国际象棋为背
景的问题: 如何能够在 8×8 的国际象棋棋盘上
放置八个皇后,使得任何一个皇后都 无法直接吃掉其他的皇后?为了达到 此目的,任两个皇后都不能处于同一 条横行、纵行或斜线上。
for(a[8]=1;a[8]<=8;a[8]++) 此算法可读性很好,
{if (check(a,8)==0)continue; 体现了“回溯”。但
else for(i=1;i<=8;i+nt(a[i]); }
题,而不能解决任意
}}}}}}}
的n皇后问题。
18
2 回溯法应用-算法说明
按什么顺序去搜? 目标是没有漏网之鱼,尽量速度快。
5
2 【问题设计】盲目的枚举算法
a 盲目的枚举算法
通过8重循环模拟搜索空间中的88个状态;
按枚举思想,以DFS的方式,从第1个皇后在第1列开 始搜索,枚举出所有的“解状态”:
从中找出满足约束条件的“答案状态”。
回溯算法与八皇后问题N皇后问题Word版
回溯算法与八皇后问题(N皇后问题)1 问题描述八皇后问题是数据结构与算法这一门课中经典的一个问题。
下面再来看一下这个问题的描述。
八皇后问题说的是在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。
更通用的描述就是有没有可能在一张N*N的棋盘上安全地放N个皇后?2 回溯算法回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。
回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满足某种要求的可能或最优的情况,从而得到整个问题的解。
回溯算法就是解决这种问题的“通用算法”,有“万能算法”之称。
N皇后问题在N增大时就是这样一个解空间很大的问题,所以比较适合用这种方法求解。
这也是N皇后问题的传统解法,很经典。
下面是算法的高级伪码描述,这里用一个N*N的矩阵来存储棋盘:1) 算法开始, 清空棋盘,当前行设为第一行,当前列设为第一列2) 在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步3) 在当前位置上满足条件的情形:在当前位置放一个皇后,若当前行是最后一行,记录一个解;若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;若当前行是最后一行,当前列不是最后一列,当前列设为下一列;若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;以上返回到第2步4) 在当前位置上不满足条件的情形:若当前列不是最后一列,当前列设为下一列,返回到第2步;若当前列是最后一列了,回溯,即,若当前行已经是第一行了,算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置,返回到第2步;算法的基本原理是上面这个样子,但不同的是用的数据结构不同,检查某个位置是否满足条件的方法也不同。
八皇后问题(回溯法)
void queen(int N)
{ //初始化N+1个元素,第一个元素不使用
int col[N+1]; //col[m]=n表示第m列,第n行放置皇后
int a[N+1]; //a[k]=1表示第k行没有皇后
int b[2*N+1]; //b[k]=1表示第k条主对角线上没有皇后
int c[2*N+1]; //c[k]=1表示第k条次对角线上没有皇后
int j,m=1,good=1;char awn;
for(j=0;j<=N;j++)
{a[j]=1;}
for(j=0;j<=2*N;j++)
{b[j]=c[j]=1;}
col[1]=1;col[0]=0;
do
{
if(good)
八皇后问题(回溯法)2009-08-11 12:03问题描述:
求出在一个n×n的棋盘上,放置n个不能互相捕捉的国际象棋“皇后”的所有布局,这是来源于国际象棋的一个问题。皇后可以沿着纵横和两条斜线4个方向互相捕捉。
解题思路:
总体思想为回溯法。
求解过程从空配置开始。在第1列~的m列为合理配置的基础上,再配置第m+1列,直至第n列也是合理时,就找到了一个解。在每列上,顺次从第一行到第n行配置,当第n行也找不到一个合理的配置时,就要回溯,去改变前一列的配置。
if(awn=='Q'||awn=='q')
exit(0);
while(col[m]==N) //如果本列试探完毕,则回溯
{
m--; //回溯
a[col[m]]=b[m+col[m]]=c[N+m-col[m]]=1;//标记m列col[m]行处没有皇后(所在行,对角线,次对角线上都没有皇后)
随机法 8皇后问题
回溯法与随机法比较: 回溯法与随机法比较:
N皇后问题一般是采用回溯法求解,但当N值 皇后问题一般是采用回溯法求解,但当 值 皇后问题一般是采用回溯法求解 较大时,回溯算法效率较低。 较大时,回溯算法效率较低。 引入随机算法, 引入随机算法,能保证每次找出的解是正确 但可能在一次求解过程中找不出可行解, 的,但可能在一次求解过程中找不出可行解,这 一点在程序运行过程中能得到体现。 一点在程序运行过程中能得到体现。 所以解决N皇后问题时, 所以解决 皇后问题时,我们可以先用随机 皇后问题时 函数产生一部分的解(这一部分可以占全部的三 函数产生一部分的解( 分之一),再用回溯法将其余的结果计算出来。 ),再用回溯法将其余的结果计算出来 分之一),再用回溯法将其余的结果计算出来。
2.回溯法与随机法结合,也就是,前k个皇后用随 2.回溯法与随机法结合,也就是, 回溯法与随机法结合 机法,后面的回溯。 机法,后面的回溯。 这样效率会提高很多。 这样效率会提高很多。 但是随机产生的k个皇后,回溯继续求解时不一定 但是随机产生的k个皇后, 能得到可行解。此时,需要重新运行算法。 能得到可行解。此时,需要重新运行算法。
姓名: 姓名:刘瑾 学号: 学号:31109016
一、8皇后问题算法描述 皇后问题算法描述
1.每个皇后放置的位置均随机 每个皇后放置的位置均随机 直接从每行的8个位置随机选择 直接从每行的 个位置随机选择 随机法 从每行的可行解中随机选择
不管用哪种随机法,都是算法一旦失败, 不管用哪种随机法,都是算法一旦失败, 就得重新运行。 就得重新运行。 算法成功,只找到一个解。 算法成功,只找到一个解。 多次成功找到的解不一定是同一个解。 多次成功找到的解不一定是同一个解。
运行结果: 运行结果:
八皇后问题
该算法的大概描述:
1.置当前行 当前列均为1 2.While当前行号(<=8) 3.检查 当前行,从当前列起逐列试探,寻找安全列号 4.If(找到安全号) 5.放置皇后,将列号记入栈中,并将下一行置成当前行,第一列置为当前列 6.否则回溯到上一行,移去该行已经放置的皇后,以该皇后所在列的下一列作为当 前列, 8结束程序。
八皇后问题
八数学家高斯1850年提出:在 8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任 意两个皇后都不能处于同一行、同一列或同一斜线上,问有 多少种摆法?八皇后在棋盘上分布的各种可能的数目非常大。 但是可以将一些明显不满足问题要求的格局排除掉,由于任 意两个皇后不可能同行,即每一行只能放置一个皇后,因此 将第i个皇后放置在第i行上。这样 在放置第i个皇后时,只要 考虑它与前i-1个皇后处于不同列和不同对角线位置上即可。
一般算法
用 数组a、b、c分别用来标记冲突,a数组代表列冲突,从a[0]~a[7]代表第0列到第 7列,如果某列上已经有皇后,则为1,否则为0; 数组b代表主对角线冲突,为b[i-j+7],即从b[0]~b[14],如果某条主对角线上已经 有皇后,则为1,否则为0; 数组c代表从对角线冲突,为c[i+j],即从c[0]~c[14],如果某条从对角线上已经有皇 后,则为1,否则为0; 从第一行起 逐个放置皇后,每放置一个皇后依次对第1,2......8列进行试探,若当 前 试探的列位置是安全的,则将该行的列位置保存在栈中,然后继续在下一行寻 找安全位置,若当前试探的列位置不安全,则用下一列进行试探,当8列的位置试 探完毕都未能找到安全位置时,就退栈回溯到上一行,修改栈顶保存的皇后位置, 然后继续试探。
八皇后问题有多少解
八皇后问题有多少解八皇后问题有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皇后同样的方法可以获得问题的解。
1213:八皇后问题
1213:⼋皇后问题【题⽬描述】在国际象棋棋盘上放置⼋个皇后,要求每两个皇后之间不能直接吃掉对⽅。
【输⼊】(⽆)【输出】按给定顺序和格式输出所有⼋皇后问题的解(见样例)。
【输⼊样例】(⽆)【输出样例】No. 11 0 0 0 0 0 0 00 0 0 0 0 0 1 00 0 0 0 1 0 0 00 0 0 0 0 0 0 10 1 0 0 0 0 0 00 0 0 1 0 0 0 00 0 0 0 0 1 0 00 0 1 0 0 0 0 0No. 21 0 0 0 0 0 0 00 0 0 0 0 0 1 00 0 0 1 0 0 0 00 0 0 0 0 1 0 00 0 0 0 0 0 0 10 1 0 0 0 0 0 00 0 0 0 1 0 0 00 0 1 0 0 0 0 0...以下省略解题分析:关键在于斜线还有是否访问过,正斜与反斜⾓的特点#include<bits/stdc++.h>using namespace std;int a[10001],b[10001],w[10001],m[10001],tot=0;int print(){tot++;cout<<"No. "<<tot<<endl;for(int j=1;j<=8;++j){for(int i=1;i<=8;++i)if(j==a[i])cout<<1<<" ";else cout<<0<<" ";cout<<endl;}}int search(int j){for(int i=1 ;i<=8;++i){if(b[i]==0&&w[i-j+7]==0&&m[i+j]==0){a[j]=i;b[i]=1;w[i-j+7]=1;m[i+j]=1;if(j==8) print();else search(j+1);b[i]=0;w[i-j+7]=0;m[i+j]=0;}}}int main(){search(1);return 0;}记住限制条件是该列有没访问过,还有斜⾓两个⽅向。
皇后问题详细的解法
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皇后问题)⼋皇后问题,是⼀个古⽼⽽著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋⼿马克斯·贝瑟尔于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个皇后放上去之后,是否无冲突。
八皇后所有可能的方案
▔▔▔▔▔▔▔▔
第 7种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█★█ █ █ ▏
▕ █ █★█ █▏
▕█ █ █ ★ ▏
▕ █ ★ █ █▏
▕★ █ █ █ ▏
▕ █ █ █ ★▏
▕█ █ █★█ ▏
▕ █ █ ★ █▏
▔▔▔▔▔▔▔▔
第14种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ ★ █ █ ▏
▕ █ █★█ █▏
▕█★█ █ █ ▏
▕ █ █ █ ★▏
▕★ █ █ █ ▏
▕ █ █ █★█▏
▕█ █★█ █ ▏
▕ █ █★█ █▏
▔▔▔▔▔▔▔▔
第33种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ █★█ █ ▏
▕ ★ █ █ █▏
▕█ █ █ ★ ▏
▕ █★█ █ █▏
▕█ █ █★█ ▏
▕ █ █ █ ★▏
▕ █ █★█ █▏
▔▔▔▔▔▔▔▔
第20种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ ★ █ █ ▏
▕ █ █ ★ █▏
▕█★█ █ █ ▏
▕ █ █ █★█▏
▕█ █ ★ █ ▏
▕★█ █ █ █▏
▕█ █ █ █★▏
▕ █ █ ★ █▏
▔▔▔▔▔▔▔▔
第27种方案(★表示皇后)
▁▁▁▁▁▁▁▁
▕█ ★ █ █ ▏
▕ █ █ █★█▏
▕█★█ █ █ ▏
▕ █ █ █ ★▏
▕█ █ █★█ ▏
▕ █ ★ █ █▏
八皇后问题(递归+非递归)
八皇后问题(递归+非递归)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;}。
综合性实验报告格式
实验报告——八皇后问题求解(递归和非递归)学号: 12022101 专业年级:海工1201 姓名:韩鸣晓一、需求分析(要实现的功能描述)1.问题描述1)八皇后问题:是一个古老而著名的问题。
该问题是十九世纪著名的数学家高斯1850年提出:在8×8棋盘上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法?2)解决八皇后问题的关键在于:(1)找到合理的数据结构存放棋子的摆放位置。
(2)要有合理的冲突检查算法。
采用的方法是,先把8个棋子摆在棋盘上,每行摆一个,然后去检查这种摆放是否有冲突,如果没有冲突,即找到了一种解决方案。
由于皇后的摆放位置不能通过某种公式来确定,因此对于每个皇后的摆放位置都要进行试探和纠正,这就是“回溯”的思想。
在8个皇后未放置完成前,每行摆放一个皇后,摆放第i 个皇后和第i+1个皇后的试探方法是相同的,因此完全可以采用递归的方法来处理。
2.实现功能实现了在棋盘上摆放八个皇后的功能,这八个皇后任意两个皇后都不能处于同一条横行、纵行或斜线上。
3.测试数据找到三组正确解,看程序运行的结果是否包含正确解:第一组:(1,1)、(2,5)、(3,8)、(4,6)、(5,3)、(6,7)、(7,2)、(8,4);第二组:(1,2)、(2,4)、(3,6)、(4,8)、(5,3)、(6,1)、(7,7)、(8,5);第三组:(1,3)、(2,6)、(3,8)、(4,2)、(5,4)、(6,1)、(7,7)、(8,5)。
二、概要设计程序总体分为两大块:(1)八皇后摆法的寻找(2)棋盘及棋子的设计。
整个程序包含功能模块及模块间的调用关系对于八皇后问题,整个程序中应该包含主函数模块,摆放皇后的函数模块,以及判断皇后的位置是否摆放正确的判断模块。
对于模块间的关系,在运行主函数的过程中会调用摆放皇后的函数模块,在摆放皇后的函数模块中,又会调用判断皇后位置是否=摆放正确的判断模块。
八皇后问题详细的解法
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]); }
题,而不能解决任意
}}}}}}}
第一讲:八皇后问题
//验证检查左上至右下某斜行是否至多有一个true public static boolean isLeftUpToRightDownOK(boolean[][] data,int i) { int count =0; for(int k=0;k<8;k++) { if (k+i<0 || k+i>=8) continue ; if (data[k][k+i]) count++ ; } return count<=1; }
代码框架
public static void solution() { Stack<ChessBoard> stack = new Stack<ChessBoard>(); stack.push( new ChessBoard() ); //空棋盘进栈 while(!stack.empty()) { ChessBoard board = stack.pop(); //取栈顶元素 if ( board 可被继续放置皇后 ) { int row = board 可在哪一行被继续放置皇后 int[] columns = board 可在该行哪几列放皇后 for(int j=0;j<columns.length;j++) { ChessBoard newBoard = 复制产生新的ChessBoard ; //放置皇后,存入堆栈 newBoard.place(row, columns[j]) ; stack.push(newBoard); } } else if (board.isAnswer()) { //栈顶元素是求解的答案,输出 board.printResult(); } } }
数据结构八皇后问题实验报告
八皇后问题一.八皇后问题简述:在8*8的国际象棋棋盘上放置8个皇后,使任意两个皇后不能互相攻击,即任何行任何列或对角线(与水平轴的夹角为45°或135°的斜线)上不得有两个或两个以上的皇后,这样的一个格局称为问题的一个解。
请求八皇后问题的算法。
二.解决思路:先声明我们根据条件可以知道皇后肯定是每行都有且只有一个所以我们创建一个数组x[t]让数组角标表示八皇后的行,用这个角标对应的数组值来确定这个皇后在这行的那一列。
我们用递归来做:这问题要求皇后所在的位置必须和其他皇后的位置不在同一行、列还有把两个皇后看成点其|斜率|=1;所以我们就要写这个限定条件用一个函数来实现:函数内对每一个已经放好的皇后的位置进行判断,所以就要有个循环。
我们既然是用递归来解决问题那就要把这个问题分成一个个相同的小问题来实现。
不难发现我们要在8*8的方格里放好8个皇后那我们就要知道在8(列)*7(行)是怎么放的在有我们事先写好的判断函数放好最后行就搞定了;以此类推我们要知道8*7的怎么方的我们就要知道8*6是怎么样的就好了,所以我们是以一行怎么放作为一个单元。
我们就去建一个可以放好一行的函数backtrack(int t)里面的t表示是第几行,在main函数调用的时候第一次传进来的是0也就是从第一行开始判断。
我们就开始写函数体了:每一行有8个位置可以放,每一个位置我们都要去判断一下所以我们就用循环来搞定。
在这个循环里面我们让x[t]=i也就是从这一行的第一个开始判断。
放好后就要去判断是否符合条件。
如果符合条件我们就在调用这个函数本身backtrack 不过传进去的参数是t+1也就是下一行的意思。
在进行判断下一行之前我们要判断一下t是不是等于8也就是已经是最后一行了,如果是最后一行了我们就可以将其进行输出。
打印8*8的矩阵(提示在写一个函数)皇后的位置用1表示出来没有的用0表示。
三.代码与注解:#include <math.h>#include <stdio.h>#include <time.h>#include<string.h>#include<conio.h> //用getch()要调用的头文件#include <stdlib.h> //要用system函数要调用的头文件int SUM=0; //统计有多少种可能int shezhi(){ //设置为N皇后问题int N;printf("这是一个N皇后问题...\n请输入N=");scanf("%d",&N);return N;}void Print(int N,int x[]) //印出結果{int MAX=N;for(int i=0;i<MAX;i++){for(int j=0;j<MAX;j++)if(j==x[i])printf("@");elseprintf("*");printf("\n");}SUM++; //打印一种情况统计一次printf("\n");}int Judge(int k,int x[]) //判断是否在同一直、橫、斜线上有其它棋子{int i;for(i=0;i<k;i++)if( abs(k-i)==abs(x[i]-x[k]) || x[i]==x[k] ) //函数名: abs; 功能: 求整数的绝对值 ;return 0;return 1;}void backtrack(int t,int N,int x[]) // 把棋子放到棋盘上{ int MAX=N;int i;for(i=0;i<MAX;i++){x[t]=i;if(Judge(t,x)){if(t==MAX-1){Print(MAX,x); // 找到其中一种放法,印出結果}else backtrack(t+1,N,x);}}}void Introduce(){printf("1.设置为N皇后问题。
(完整word版)数据结构课程设计之_八皇后问题
课程设计报告课程名称数据结构课程设计课题名称八皇后问题演示专业通信工程班级通信工程1081学号201013120103姓名刘献文指导教师田娟秀郭芳2012年7 月 6 日湖南工程学院课程设计任务书课程名称数据结构课题八皇后问题演示专业班级通信工程1081学生姓名刘献文学号201013120103指导老师田娟秀郭芳审批任务书下达日期2012 年7 月 1 日任务完成日期2012 年7 月 6 日1设计内容与设计要求1。
1设计内容(4)课题四:八皇后问题演示八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。
该问题是十九世纪著名的数学家高斯1850年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
高斯认为有76种方案。
1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
设计思路: 解决8皇后时,在安放第i行皇后时,需要在列的方向从1到n试探(j =1,…, n):首先在第j列安放一个皇后,如果在列、主对角线、次对角线方向有其它皇后,则出现攻击,撤消在第j列安放的皇后。
如果没有出现攻击,在第j列安放的皇后不动,递归安放第i+1行皇后。
对于八皇后问题的实现,如果结合动态的图形演示,则可以使算法的描述更形象、更生动.要求用Turbo C或VC6.0 MFC实现的八皇后问题的图形程序,能够演示全部的92组解.1。
2 选题方案:所选题目根据学号确定,学号模6加1,即(学号%6+1).如你的学号为9,则所选题目号为:9%6+1=(题目4)。
注意,所有的课题都要求用图形方式演示步骤和结果。
同学们可以自己针对数据结构课程中所讲算法来设计一个演示过程的算法。
1.3设计要求:1。
3.1 课程设计报告规范(1)需求分析a.程序的功能。
b.输入输出的要求。
(2)概要设计a.程序由哪些模块组成以及模块之间的层次结构、各模块的调用关系;每个模块的功能。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
八皇后问题文档
一,问题描述
能否在空棋盘上摆放八个皇后,使他们不互相侵犯,即任意的两个皇后不能在同一行或者是同一列。
二,算法思路
由于行坐标可看作不变的量,因此只要找出来不同的列坐即可,由于列坐标一定是从1到8 的序列,而且这些数字仅出现一次,因此用递归找到所有的序列,其中,把整个棋盘看作一个坐标轴,当有两点的斜率等于正负一或者为零和无穷大时,将他们跳过,直到遍历完成,打印这个序列,那么就可以得到皇后的放置方法。
三,算法描述
1,所调用的库函数
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#define num 8
2,有一个检查斜率的函数check。
他的用途是检查这个8位数列是否满足斜率为正负一和零的情况,如果是的话,返回0,否则返回1。
int check(int k[])
{
int n,m;
for (n=0;n<7;n++)
for (m=n+1;m<8;m++)
if
(k[m]<1||k[m]>8||k[n]==k[m]||abs(k[n]-k[m])==abs(n-m)) //计算其两个相邻点斜率K,并且返回他的值K[m]<1或K[m]>8时,那么就可以认为他的斜率不存在了,由于斜率是传递的,所以可以这样检测,得到应有的情况
return(0);
return(1);
}
3,main函数
main()
{
int board[num]={8,7,6,5,4,3,2,1},j=0,*ptr;
/*board[num]代表棋盘上八行,由于八个皇后在棋盘上一定是每行一个,而且横坐标一定各不相同,即1--->8各出现一次,只要检测这些数列就可以找到八皇后的所有可能情况*/
for (ptr=board;board[7]<9;board[0]+=9)
{
for (ptr=board;ptr<&board[7];)
/*对12345678每次加9,直加到87654321*/
{
if (*ptr>9)
{
*(ptr+1)+=1;
*ptr-=10;
ptr++;
}
else
ptr+=8;
}
//向下一个进行,如果大于9的话,减十再作check
if (check(board))
/*检测八位数列,返回值为真则在屏幕上输出*/
{
for (ptr=board;ptr<=&board[7];ptr++)
printf("%d",*ptr);
printf("\n");
}
}
system("pause");
return 0;
}
4,测试报告
最终出现92种情况,随机取出十组检验,发现是可行的。
5,结论和心得
经过这次编程,再次熟悉了递归调用,强化了对递归的理解,并且发现了递归的简便之处以及其运用,以后还要认真学习递归。
并且学会了要耐心的调试程序。