八皇后问题地解决完整文档
- 格式:doc
- 大小:144.96 KB
- 文档页数:17
⼋皇后问题(经典算法-回溯法)问题描述:⼋皇后问题(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;}。
算法⼊门经典-第七章例题7-2⼋皇后问题原本利⽤回溯思想解决的经典⼋皇后问题,其实也是可以⽤递归解决的~⼋皇后的递归解决思路:从第⼀⾏开始,依次判断0~8列的哪⼀列可以放置Queen,这样就确定了该⾏的Queen的位置,然后⾏数递增,继⽽递归实现下⼀⾏的判断,依次类推直到⾏数增加到8(⾏数从0开始的),此时为递归-----归的条件,即表⽰⼀种⼋皇后的解决⽅法完成,打印结果;之后进⾏下⼀种解决⽅法的寻找,⼤致思路个⼈理解是这样noDanger(row,j,(*chess)[8])函数是判断第row⾏第j列是否可以放置Queen#include<stdio.h>int count=0;//参数row:起始⾏//参数n:表⽰列数//参数(*chess)[8]表⽰指向棋盘每⼀⾏的指针int NotDanger(int row,int j,int (*chess)[8])//⽐较不同⾏同列上是否有其他皇后{int i,k,flag1=0,flag2=0,flag3=0,flag4=0,flag5=0;//判断列⽅向for(i=0;i<8;i++){if(*(*(chess+i)+j)!=0) //在这之前列上有其他皇后{flag1=1;break;}}for(i=row,k=j;i>=0&&k>=0;i--,k--){if(*(*(chess+i)+k)!=0) //左上⽅{flag2=1;break;}}for(i=row,k=j;i<8&&k<8;i++,k++){if(*(*(chess+i)+k)!=0) //右下⽅{flag3=1;break;}}for(i=row,k=j;i>=0&&k<8;i--,k++){if(*(*(chess+i)+k)!=0) //右上⽅{flag4=1;break;}}for(i=row,k=j;i<8&&k>=0;i++,k--){if(*(*(chess+i)+k)!=0) //左下⽅{flag5=1;break;}}if(flag1||flag2||flag3||flag4||flag5){return0;//如果有⼀个位置被占有危险}else return1;} /*int noDanger(int row,int j,int (*chess)[8]){int flag1=0,flag2=0,flag3=0,flag4=0,flag5=0;int i,k;//判断列for(i=0;i<8;i++){if(*(*(chess+i)+j)!=0){flag1=1;break;}}//判断左上⽅for(i=row,k=j;i>=0&&k>=0;i--,k--){if(*(*(chess+i)+k)!=0){flag2=1;break;}}//判断右下⽅for(i=row,k=j;i<8&&k<8;i++,k++){if(*(*(chess+i)+k)!=0){flag3=1;break;}}//判断左下⽅for(i=row,k=j;i<8&&k>=0;k--,i++){if(*(*(chess+i)+k)!=0){flag4=1;break;}}//判断右上⽅for(i=row,k=j;i>=0&&k<8;k++,i--){if(*(*(chess+i)+k)!=0){flag5=1;break;}}if(flag1||flag2||flag3||flag4||flag5){return 0;}else{return 1;}} */EightQueen(int row,int n,int (*chess)[8]){int chess2[8][8];int i,j;for(i=0;i<8;i++){for(j=0;j<8;j++){chess2[i][j]=chess[i][j];}}if(8==row){printf("第%d 种\n",count+1);for(i=0;i<8;i++){for(j=0;j<8;j++)printf("%3d ",*(*(chess2+i)+j));printf("\n");}count++;}else{//判断这个位置是否危险 j<列for(j=0;j<n;j++){if(NotDanger(row,j,chess2))//尝试每⼀列是否危险 {for(i=0;i<8;i++){//整⾏所有列的位置赋值为0*(*(chess2+row)+i)= 0;}*(*(chess2+row)+j)=1;//皇后的位置赋值为1EightQueen(row+1,n,chess2);//继续往下⼀⾏递归 }}}}int main(){int chess[8][8],i,j;for(i=0;i<8;i++){for(j=0;j<8;j++)chess[i][j]=0;}EightQueen(0,8,chess);printf("总共有%d种解决⽅法",count);return0;}。
数据结构实验报告实验名称:实验2 利用栈结构实现八皇后问题学生姓名:廖宁班级:2009211114班内序号:18学号:09210411日期:2010年11月18日1.实验要求八皇后问题是19世纪著名的数学家高斯于1850年提出的。
他的问题是:在8*8的棋盘上放置8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列、同一斜线上。
请设计算法打印所有可能的摆放方法。
提示:(1)可以使用递归或非递归两种方法实现。
(2)实现一个关键算法,判断任意两个皇后是否在同一行、同一列和同一斜线上。
2. 程序分析程序工程包含一个模板类函数实现定义的源文件forthelove.cpp和测试源文件sbsuowang.cpp。
2.1 存储结构存储结构为栈。
2.2 关键算法分析(1)判断在第row行第column列摆放皇后是否非法,采取定行不定列的方法,列相等的算法为position[i]=colume,对角线相等有两种情况:一是position在上则row-i=colume-position[i];二是position在下,row-i=position[i]-colume.加入能放皇后,列和对角线上值都不能相等。
具体代码如下:int IsIllegal(int row, int column, const int* position){/int i;for (i=1; i < row; ++i){if ((position[i] == column)|| (row - i == column - position[i])|| (row - i == position[i] - column)){return TRUE;}}return FALSE;}(2)我采用定行尝试列的方法来遍历,记录皇后位置的数组可以和栈数组合二为一,而栈顶指针也可以和行坐标合二为一,这样一来栈帧只要一个列坐标就可以了。
1.伪代码:while(栈不空){if ( 行(即栈顶) <= n && 列<= n ){if ( 当前位置不能放皇后){列++;}else{列入栈(隐含着"行++");列= 1;}}else{if ( 行(即栈顶) > n ){输出位置数组(即栈数组);}列退栈(隐含着"行--");列++;}}//end while具体实现代码:void Queens(int n, void (* Visit)(const int* position)) {//position[n]数组:position[0]为棋盘大小,即n//position[1]~position[n]:下标为行坐标,值为列坐标int* stack = NULL; //栈int top; //栈顶int column; //列stack = (int*)malloc((n + 1) * sizeof(int));stack[0] = n;top = column = 1;while(top > 0){if ((top <= n) && (column <= n)){if (IsIllegal(top, column, stack)){++column;}else{stack[top++] = column;column = 1;}}else{if (top > n){(* Visit)(stack);}column = stack[--top];++column;}}//end whilefree(stack);return;}3. 程序运行结果程序实现八皇后问题:经过测试,程序运行良好,无明显错误。
⼋皇后以及N皇后问题分析⼋皇后是⼀个经典问题,在8*8的棋盘上放置8个皇后,每⼀⾏不能互相攻击。
因此拓展出 N皇后问题。
下⾯慢慢了解解决这些问题的⽅法:回溯法:回溯算法也叫试探法,它是⼀种系统地搜索问题的解的⽅法。
回溯算法的基本思想是:从⼀条路往前⾛,能进则进,不能进则退回来,换⼀条路再试。
在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满⾜某种要求的可能或最优的情况,从⽽得到整个问题的解。
回溯算法就是解决这种问题的“通⽤算法”,有“万能算法”之称。
N皇后问题在N增⼤时就是这样⼀个解空间很⼤的问题,所以⽐较适合⽤这种⽅法求解。
这也是N皇后问题的传统解法,很经典。
算法描述:1. 算法开始,清空棋盘。
当前⾏设为第⼀⾏,当前列设为第⼀列。
2. 在当前⾏,当前列的判断放置皇后是否安全,若不安全,则跳到第四步。
3. 在当前位置上满⾜条件的情况: 在当前位置放⼀个皇后,若当前⾏是最后⼀⾏,记录⼀个解; 若当前⾏不是最后⼀⾏,当前⾏设为下⼀⾏,当前列设为当前⾏的第⼀个待测位置; 若当前⾏是最后⼀⾏,当前列不是最后⼀列,当前列设为下⼀列; 若当前⾏是最后⼀⾏,当前列是最后⼀列,回溯,即清空当前⾏以及以下各⾏的棋盘,然后当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置; 以上返回第⼆步。
4.在当前位置上不满⾜条件: 若当前列不是最后⼀列,当前列设为下⼀列,返回到第⼆步; 若当前列是最后⼀列,回溯,即,若当前⾏已经是第⼀⾏了,算法退出,否则,清空当前⾏以及以下各⾏的棋盘,然后,当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置,返回第⼆步。
如何判断是否安全:把棋盘存储为⼀个N维数组a[N],数组中第i个元素的值代表第i⾏的皇后位置,这样便可以把问题的空间规模压缩为⼀维O(N),在判断是否冲突时也很简单, ⾸先每⾏只有⼀个皇后,且在数组中只占据⼀个元素的位置,⾏冲突就不存在了, 其次是列冲突,判断⼀下是否有a[i]与当前要放置皇后的列j相等即可。
C++实现八皇后问题及其扩展N皇后问题(经典回溯算法)八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。
该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
高斯认为有76种方案。
1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。
该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
高斯认为有76种方案。
1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
事实上就是有92种解法。
了解了基本的原理后,我们开始分析:1.我们需要一个数据存放已经放置皇后的位置,用指针表示的一维数据*position,长度为N(N为放置的皇后总数),可能有人会问为什么不用二维数组,用下票i,j准备定位,事实是这样的,因为该问题是每行,每列,每组对角线只可能出现一个皇后,所以用一维数据position+i中的i则能代码第几行,而值*(position+i)则表示该行中的列值,其实质与二维数组无异.2.判断每行可放置皇后,假设要判断第n行,则从position中从0到n-1每一个已放皇后的位置判断(列,对角线)具体算法如下:#include <iostream>#include <math.h>#include <malloc.h>using namespace std;int *position; //放置的位置int queen; //皇后数目int count; //第N种可能性//判断第n行是否放置皇后bool SignPoint(int n){for (int i=0;i<n;i++){if (*(position+i) == *(position+n)) //该列已经放置过皇后了return false;if (abs(*(position+i) - *(position+n)) == n-i) //对角线已经放置过了return false;}return true;}//设置皇后void SetQueen(int n=0){if (queen==n){//该处可以改成自己想要的显示方式printf("NO.%d: ",++count);printf("\n");for (int i=0;i<queen;i++){for (int j=0;j<queen;j++){if (j == position[i]){printf("* ");}else{printf("0 ");}}printf("\n");}printf("\n");return;}else{for (int i=0;i<queen;i++){position[n] = i;if(SignPoint(n))//如果该位置放置皇后正确的话,则到下一行{SetQueen(n+1);}}}}int main(int argc, char * argv[]){cout<<"请输入皇后的总数:"<<endl;cin>>queen;position = (int*)malloc(sizeof(int));SetQueen();cout<<"摆放完毕"<<endl;cin.get();cin.get();return 0;}。
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;}记住限制条件是该列有没访问过,还有斜⾓两个⽅向。
算法设计与分析实验报告实验名称:用回溯法解决八皇后问题姓名:学号:江苏科技大学一、实验名称:回溯法求解8皇后问题二、学习知识:回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
回溯法是一个既带有系统性又带有跳跃性的搜索算法。
它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解的空间树。
算法搜索至解的空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。
如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。
否则,进入该子树,继续按深度优先的策略进行搜索。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。
这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。
三、问题描述(1)使用回溯法解决八皇后问题。
8皇后问题:在8*8格的棋盘上放置彼此不受攻击的8个皇后。
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
8后问题等价于在8*8格的棋盘上放置8个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
(2)用高级程序设计语言实现四、求解思路Procedure PLACE(k)//如果一个皇后能放在第k行和X(k)列,则返回true,否则返回false。
X是一个全程数组,进入此过程时已置入了k个值。
ABS(r)过程返回r的绝对值//global X(1:k); integer i,k;i←1while i<k doif X(i)=X(k) or ABS(X(i)-X(k))=ABS(i-k) thenreturn (false)end ifi←i+1repeatreturn (true)End PLACEProcedure NQUEENS(n)//此过程使用回溯法求出一个n*n棋盘上放置n个皇后,使其不能互相攻击的所有可能位置//integer k,n,X(1:n)X(1)←0 ; k←1 // k是当前行;X(k)是当前列 //while k>0 do // 对所有的行,执行以下语句 //X(k)←X(k)+1 //移到下一列//while X(k)<=n and Not PLACE(k) do //此处能放这个皇后吗//X(k)←X(k)+1 //不能放则转到下一列//repeatif X(k)<=n then //找到一个位置//if k=n then print (X) //是一个完整的解则打印这个数组// else k←k+1;X(k)←0 //否则转到下一行//end ifelse k←k-1 //回溯//end ifrepeatEnd NQUEENS五、算法实现本实验程序是使用C#编写,算法实现如下:1.queen类—实现8皇后问题的计算,将结果存入数组。
回溯法(8皇后问题)1.1算法原理回溯算法实际是一个类似枚举的搜索尝试方法,其基本思想是在搜索尝试中找问题的解,采用了一种“走不通就掉头”的思想,作为其控制结构。
从一条路往前走,能进则进,不能进则退回来,换一条路再试。
八皇后问题就是回溯算法的典型,第一步按照顺序放一个皇后,然后第二步符合要求放第2个皇后,如果没有符合条件的位置符合要求,那么就要改变第一个皇后的位置,重新放第2个皇后的位置,直到找到符合条件的位置就可以了。
回溯在迷宫搜索中使用很常见,就是这条路走不通,然后返回前一个路口,继续下一条路。
回溯算法说白了就是穷举法。
不过回溯算法使用剪枝函数,剪去一些不可能到达最终状态(即答案状态)的节点,从而减少状态空间树节点的生成。
回溯法是一个既带有系统性又带有跳跃性的的搜索算法。
它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。
算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。
如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。
否则,进入该子树,继续按深度优先的策略进行搜索。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。
用回溯法搜索解空间树时,通常采用两种策略来避免无效搜索,提高回溯法的搜索效率。
其一是用约束函数在扩展结点处剪去不满足约束的子树;其二是用限界函数剪去不能得到最优解的子树。
1.2算法适用性它适用于解一些组合数较大的问题,有条件限制的枚举,即优化的枚举.1.3算法描述8皇后回溯算法1.设Column[8]数组依次存储第一行到第八行的列位置,QUEEN_NUM=8,皇后个数2.从第一行第一列开始放置,开始放置下一行的皇后(当且仅当前行的皇后位置正确时)3.判断放置位置是否合理:Column[i]==Column[n],判断是否在同一列,abs(Column[i]-Column[n])==(n-i)),判断时候在斜线上。
八皇后问题的解决完整 Standardization of sany group #QS8QHH-HHGX8Q8-GNHHJ8-HHMHGN#淮阴工学院数据结构课程设计报告设计题目:八皇后2008 年 6 月 25 日设计任务书摘要:八皇后问题要求在一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击.按照国际象棋的规则,一个皇后可以攻击与之处在同一行或同一列或同一斜线上的其他任何棋子.因此,八皇后问题等于要求八个皇后中的任意两个不能被放在同一行或同一列或同一斜线上。
而本课程设计本人的目的也是通过用c++语言平台将一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击的92种结构予以实现.使用递归方法最终将其问题变得一目了然,更加易懂。
关键词:八皇后 ; c++ ; 递归法目录.1. 课题综述1. 1课题的来源及意义八皇后问题是一个古老而着名的问题,该问题是十九世纪着名的数学家高斯1850年提出的。
在国际象棋中,皇后是最有权利的一个棋子;只要别的棋子在它的同一行或同一列或同一斜线(正斜线或反斜线)上时,它就能把对方棋子吃掉。
所以高斯提出了一个问题:在8*8的格的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后都不能处于同一列、同一行、或同一条斜线上面,问共有多少种解法。
到了现代,随着计算机技术的飞速发展,这一古老而有趣的数学游戏问题也自然而然的被搬到了计算机上。
运用所学计算机知识来试着解决这个问题是个锻炼和提高我自己编程能力和独立解决问题能力的好机会,可以使我增强信心,为我以后的编程开个好头,故我选择了这个有趣的课题。
1. 2 面对的问题1)解决冲突问题:这个问题包括了行,列,两条对角线;列:规定每一列放一个皇后,不会造成列上的冲突;行:当第I行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以I为下标的标记置为被占领状态;2)使用数据结构的知识,用递归法解决问题。
⼋皇后问题—经典回溯算法⼋皇后问题⼋皇后问题,是⼀个古⽼⽽著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋⼿马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放⼋个皇后,使其不能互相攻击,即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上,问有多少种摆法。
⾼斯认为有76种⽅案。
1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有⼈⽤图论的⽅法解出92种结果。
回溯算法思想回溯算法的基本思想是:从⼀条路往前⾛,能进则进,不能进则退回来,换⼀条路再试。
⼋皇后问题就是回溯算法的典型,第⼀步按照顺序放⼀个皇后,然后第⼆步符合要求放第2个皇后,如果没有位置符合要求,那么就要改变第⼀个皇后的位置,重新放第2个皇后的位置,直到找到符合条件的位置就可以了。
回溯在迷宫搜索中使⽤很常见,就是这条路⾛不通,然后返回前⼀个路⼝,继续下⼀条路。
回溯算法说⽩了就是穷举法。
不过回溯算法使⽤剪枝函数,剪去⼀些不可能到达最终状态(即答案状态)的节点,从⽽减少状态空间树节点的⽣成。
回溯法是⼀个既带有系统性⼜带有跳跃性的的搜索算法。
它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。
算法搜索⾄解空间树的任⼀结点时,总是先判断该结点是否肯定不包含问题的解。
如果肯定不包含,则跳过对以该结点为根的⼦树的系统搜索,逐层向其祖先结点回溯。
否则,进⼊该⼦树,继续按深度优先的策略进⾏搜索。
回溯法在⽤来求问题的所有解时,要回溯到根,且根结点的所有⼦树都已被搜索遍才结束。
⽽回溯法在⽤来求问题的任⼀解时,只要搜索到问题的⼀个解就可以结束。
这种以深度优先的⽅式系统地搜索问题的解的算法称为回溯法,它适⽤于解⼀些组合数较⼤的问题。
⼋皇后实现⼆以下实现是极客时间王争的解法,⾮常巧妙,思路也⾮常清晰,如果理解了⼋皇后问题的本质后建议采⽤该⽅法,代码实现如下:#include <iostream>int queenPlace[8] = { 8 }; //全局变量,下标表⽰⾏,值表⽰queen存储在那⼀列int count = 0; //计数器void printQueen() { //打印⼀个⼆维数组for (int i = 0; i < 8; ++i) {for (int j = 0; j < 8; ++j) {if (queenPlace[i] == j) {printf("Q ");} else {printf("* ");}}printf("\n");}printf("----count:%d-----\n", ++count);}bool isOk(int row, int col) { //判断row⾏col列放置是否合适int leftUp = col - 1; //左上对⾓线int rightUp = col + 1; //右上对⾓线for (int i = row - 1; i >= 0; --i) {if (queenPlace[i] == col) return false; //同列上的格⼦有皇后if (leftUp >= 0) {if (queenPlace[i] == leftUp) return false; //左上对⾓线有皇后}if (rightUp < 8) {if (queenPlace[i] == rightUp) return false; //右上对⾓线有皇后}--leftUp; ++rightUp;}return true;}void eightQueen(int row) {if (row == 8) { //8个皇后都放置好,打印,⽆法递归返回printQueen();return;}for (int col = 0; col < 8; ++col) { //每⼀⾏都有8种⽅法if (isOk(row, col)) { //满⾜要求queenPlace[row] = col; //第row⾏的皇后放在col列eightQueen(row+1); //考察下⼀⾏}}}int main() {eightQueen(0);return0;class Solution {public:vector<vector<string>> res;vector<int> n_queen;vector<vector<string>> solveNQueens(int n) {n_queen.resize(n);backtrack(0);return res;}void backtrack(int row) {if (row == n_queen.size()) {storeResult();return;}for (int i = 0; i < n_queen.size(); ++i) {if (!isOk(row, i)) continue;n_queen[row] = i;backtrack(row + 1);}}bool isOk(int row, int col) {int left_up = col - 1;int right_up = col + 1;for (int i = row - 1; i >= 0; --i) {if (n_queen[i] == col // 当前列|| n_queen[i] == left_up-- // 左上对⾓,⽆需判断 left_up < 0, 该情况不会成⽴的 || n_queen[i] == right_up++) { // 右上对⾓,⽆需判断 right_up > n_queen.size() return false;}}return true;}void storeResult() {vector<string> result;for (auto i : n_queen) {string s(n_queen.size(), '.');s[i] = 'Q';result.push_back(s);}res.push_back(result);}};解法2:class Solution {public:vector<bool> col;vector<bool> dia1;vector<bool> dia2;vector<vector<string>> result;vector<string> generateQueen(vector<int>& q){vector<string> res;for (int i = 0; i < q.size(); ++i){string s(q.size(), '.');s[q[i]] = 'Q';res.push_back(s);}return res;}void traceBack(int n, int row, vector<int>& q){if (row == n) {result.push_back(generateQueen(q));return;}for (int i = 0; i < n; ++i){if (!col[i] && !dia1[row + i] && !dia2[row - i + n - 1]){q.push_back(i);col[i] = true;dia1[row + i] = true;dia2[row - i + n - 1] = true;traceBack(n, row + 1, q);col[i] = false;dia1[row + i] = false;dia2[row - i + n - 1] = false;q.pop_back();}}vector<vector<string>> solveNQueens(int n) { col = vector<bool>(n, false);dia1 = vector<bool>(2 * n - 1, false);dia2 = vector<bool>(2 * n - 1, false);vector<int> q;traceBack(n, 0, q);return result;}};。
八皇后问题(递归+非递归)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;}。
淮阴工学院数据结构课程设计报告设计题目:八皇后2008 年 6 月25 日设计任务书课题名称八皇后设计目的1.用c++语言平台将一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击的92种结构予以实现.2.通过这次课程设计,提高自己的编程能力,熟悉c++的编程坏境,为以后的程序开发打下基础.实验环境1)系统要求:win98以上操作系统;2)语言平台:tc++或vc++6.0;3)执行文件:八皇后.exe任务要求试编写程序实现将八个皇后放置在国际象棋棋盘的无冲突的位置上的算法,并给出所有的解。
工作进度计划序号起止日期工作内容1 2008.6.23~2008.6.24查阅相关内容2 2008.6.24~2008.6.25编写代码及实习报告3 2008.6.25~2008.6.26完善课程设计报告4 2008.6.26~2008.6.27答辩指导教师(签章):2008 年 6 月30 日摘要:八皇后问题要求在一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击.按照国际象棋的规则,一个皇后可以攻击与之处在同一行或同一列或同一斜线上的其他任何棋子.因此,八皇后问题等于要求八个皇后中的任意两个不能被放在同一行或同一列或同一斜线上。
而本课程设计本人的目的也是通过用c++语言平台将一个8*8的棋盘上放上8个皇后,使得每一个皇后既攻击不到另外七个皇后,也不被另外七个皇后所攻击的92种结构予以实现.使用递归方法最终将其问题变得一目了然,更加易懂。
关键词:八皇后; c++; 递归法目录1. 课题综述 (1)1.1课题的来源及意义 (1)1.2面对的问题 (1)2. 需求分析 (1)2.1涉及到的知识 (1)2.2软硬件的需求 (1)2.3功能需求 (2)3. 概要设计 (2)4. 详细设计和实现 (2)4.1算法描述及详细流程图 (2)4.1.1算法描述 (3)4.1.2算法流程图 (3)5. 代码编写及详细注释 (4)6. 程序调试 (7)6.1调试过程、步骤及遇到的问题 (7)7. 运行与测试 (7)7.1运行演示 (7)总结 (9)致谢 (10)参考文献 (11).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语言的方向发展,不自觉的采用了非递归的算法,结果大大增加了程序的复杂程度。
并且也让整个程序的时间复杂度变得更大;在后来学生对数据结构的第六章进行了比较深入的研读,才发现了数据结构树的实际运用的空间是相当的大,并且,通过了重温树的回溯,以及二叉树的遍历,最终将程序进行了一次较大的改造。