递归算法实现“八皇后问题”

合集下载

组合数学中的棋盘问题

组合数学中的棋盘问题

组合数学中的棋盘问题棋盘问题是组合数学中一个经典而又有趣的问题,它涉及到在一个n × n 的棋盘上放置一定数量的棋子并满足特定的条件。

在本文中,我们将探讨棋盘问题的一些常见形式以及解决方法。

一、八皇后问题八皇后问题是指在一个 8 × 8 的棋盘上放置 8 个皇后,并且每个皇后都不能相互攻击,即任意两个皇后不得处于同一行、同一列或同一对角线上。

这个问题可以通过回溯法来解决。

我们可以逐行放置皇后,并在每一行中使用循环判断每个格子是否满足条件。

如果满足条件,则继续递归下一行;如果不满足条件,则回溯到上一行继续判断。

当所有皇后都放置完毕时,即找到了一种解法。

二、骑士周游问题骑士周游问题是指在一个 n × n 的棋盘上,骑士按照国际象棋中骑士的移动规则进行移动,需要从起始格子出发,经过棋盘的每个格子,最终回到起始格子,且每个格子只能经过一次。

这个问题可以通过深度优先搜索或者广度优先搜索来解决。

我们可以从起始格子开始,按照骑士的移动规则依次遍历所有相邻的格子,并标记已访问的格子。

当所有格子都被访问过,并且最后的格子可以与起始格子连通,则找到了一种解法。

三、数独问题数独问题是指在一个 9 × 9 的棋盘上填入数字,使得每一行、每一列和每一个 3 × 3 的小方格中的数字都是 1 到 9 的不重复数字。

这个问题可以通过回溯法来解决。

我们可以逐格填入数字,并在每个格子中使用循环判断每个数字是否满足条件。

如果满足条件,则继续递归下一个格子;如果不满足条件,则尝试下一个数字。

当所有格子都填满时,即找到了一种解法。

四、六角形拼图问题六角形拼图问题是指在一个六角形的棋盘上,使用特定形状的六角形块填满整个棋盘。

这个问题可以通过搜索算法来解决。

我们可以从一个起始位置开始,依次尝试放置不同形状的六角形块。

每次放置块后,判断是否满足放置要求。

如果满足要求,则继续递归下一个位置;如果不满足要求,则尝试下一个形状的块。

java递归求八皇后问题解法

java递归求八皇后问题解法

java递归求⼋皇后问题解法⼋皇后问题⼋皇后问题,是⼀个古⽼⽽著名的问题,是回溯算法的典型案例。

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

⾼斯认为有76种⽅案。

1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有⼈⽤图论的⽅法解出92种结果。

⽹上有很多⼋皇后的⼩游戏,不清楚规则的可以体验⼀把。

递归理解由于我们使⽤经典的递归回溯算法,所以要先理解递归的调⽤过程,在使⽤递归前我们先看下普通⽅法的调⽤过程在JVM中如何体现。

⾸先我们来看下jvm中五个重要的空间,如下图所⽰这⾥我们主要关注栈区,当调⽤某个⽅法时会在栈区为每个线程分配独⽴的栈空间,⽽每个⽅法都会以栈帧的形式压⼊栈中,即每个⽅法从进⼊到退出都对应着⼀个栈帧的压栈和出栈。

如下图所⽰在每个栈帧中都会有⽅法独⽴的局部变量表,操作数栈,动态连接,返回地址等信息。

如下图所⽰理解了jvm程序栈的结构后,下⾯我们以图解的⽅式先讲解⼀下普通⽅法(理解普通⽅法调⽤过程后,再讲解递归的调⽤过程)的调⽤过程。

假设程序main⽅法⾸先调⽤了method1,在method1中调⽤了method2,在method2中调⽤method3。

代码如下1public static void main(String []args){2 method1();3 }5private static void method1(){6 System.out.println("method1调⽤开始");7 method2();8 System.out.println("method1调⽤结束");9 }1011private static void method2(){12 System.out.println("method2调⽤开始");13 method3();14 System.out.println("method2调⽤结束");15 }16private static void method3(){17 System.out.println("method3调⽤开始");18 System.out.println("method3调⽤结束");19 } 当执⾏main⽅法时,会执⾏以下步骤 1)⾸先将main⽅法压⼊栈中,在main⽅法中调⽤method1,⽅法mehod1会压⼊栈中,并执⾏打印“method1调⽤开始” 2)执⾏到第7⾏时,将method2压⼊栈中,执⾏method2⽅法的代码打印出“method2调⽤开始” 3)执⾏到第13⾏时调⽤method3⽅法,将method3⽅法压⼊栈中,执⾏method3⽅法打印“method3调⽤开始”,⽅法压⼊栈中的过程图解,如下图所⽰ 当执⾏到图4中的method3⽅法打印出“method3调⽤开始”后会执⾏以下步骤 1)method3执⾏打印“method3调⽤结束”后method3⽅法体已全部执⾏完毕,method3⽅法会出栈,并根据栈帧中程序计数器记录的调⽤者调⽤本⽅法的所在⾏返回。

算法——八皇后问题(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种棋盘摆法!。

八皇后问题详细的解法

八皇后问题详细的解法

若无法放下皇后则回到上一行, 即回溯
当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列开 始搜索,枚举出所有的“解状态”:
从中找出满足约束条件的“答案状态”。

八皇后实验报告

八皇后实验报告

八皇后实验报告八皇后实验报告引言:八皇后问题是一个经典的数学问题,它要求在一个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)```四、实验结果:通过运行上述算法,我们得到了八皇后问题的所有解。

算法设计与分析实验报告—八皇后问题

算法设计与分析实验报告—八皇后问题

算法设计与分析实验报告—八皇后问题-姓名:***学号:********班级:软件83【问题描述】在国际象棋盘上放八个皇后,要求任一皇后吃不到别人,也不受其他皇后的攻击,求出问题的所有解。

【问题分析&算法设计】用8元组x[1: n]表示8后问题。

其中x[ i]表示皇后i放在棋盘的第i行的第x[ i]列。

由于不允许将2个皇后放在一列,所以解向量中的x[ i]互不相同。

2个皇后不能放在同一斜线上是问题的隐约束。

故若2个皇后放置的位置分别是(i,j)和(k,l),且i – j = k – l或i + j = k + l,则说明这2个皇后处于同一斜线上。

这两个方程分别等价于i – k = j – l和i – k = l – j。

由此可知,只要|i - k| = |j - l|成立,就表明2个皇后位于同一条斜线上。

问题的隐约束化成了显约束。

用回溯法解决8皇后问题时,用完全8叉树表示解空间。

【算法实现】#include "stdio.h"#include "math.h"#include "iostream.h"#define N 8 /* 定义棋盘大小*/static int sum; /* 当前已找到解的个数*/static int x[N]; /* 记录皇后的位置,x[i]表示皇后i放在棋盘的第i行的第x[i]列*//* 每找到一个解,打印当前棋盘状态*/void Show(){sum++;cout << "第" << sum << "种情况:" << endl;cout << "坐标为:\t";for(int k = 0; k < N; k++)cout << '(' << k+1 << ',' << x[k] << ") ";cout << endl;cout << "---------------------------------\n";for (int i = 0; i < N; i ++){for (int j = 0; j < N; j ++)if (j == x[i]) //printf("@ ");cout << "* | ";else //printf("* ");cout << " | ";cout << "\n---------------------------------\n";}}/* 确定某一位置皇后放置与否,放置则返回1,反之返回0 */int Judge(int k){// 测试皇后k在第k行第x[k]列时是否与前面已放置好的皇后相攻击。

数据结构与算法中的“递归”——用回溯法求解8皇后问题

数据结构与算法中的“递归”——用回溯法求解8皇后问题

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

该问题是十九世纪德国著名数学家高斯于1850年提出的:在8行8列的国际象棋棋盘上摆放着八个皇后。

若两个皇后位于同一行、同一列或同一对角线上,则称为它们为互相攻击。

在国际象棋中皇后是最强大的棋子,因为它的攻击范围最大,图6-15显示了一个皇后的攻击范围。

图6-15 皇后的攻击范围现在要求使这八个皇后不能相互攻击,即任意两个皇后都不能处于同一行、同一列或同一对角线上,问有多少种摆法。

高斯认为有76种方案。

1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

现代教学中,把八皇后问题当成一个经典递归算法例题。

图6-16显示了两种八个皇后不相互攻击的情况。

图6-16八个皇后不相互攻击的情况现在来看如何使用回溯法解决八皇后问题。

这个算法将在棋盘上一列一列地摆放皇后直到八个皇后在不相互攻击的情况下都被摆放在棋盘上,算法便终止。

当一个新加入的皇后因为与已经存在的皇后之间相互攻击而不能被摆在棋盘上时,算法便发生回溯。

一旦发生这种情况,就试图把最后放在棋盘上的皇后移动到其他地方。

这样做是为了让新加入的皇后能够在不与其它皇后相互攻击的情况下被摆放在棋盘的适当位置上。

例如图6-17所示的情况,尽管第7个皇后不会与已经放在棋盘上的任何一皇后放生攻击,但仍然需要将它移除并发生回溯,因为无法为第8个皇后在棋盘上找到合适的位置。

图6-17 需要发生回溯的情况算法的回溯部分将尝试移动第7个皇后到第7列的另外一点来为第8个皇后在第8列寻找一个合适的位置。

如果第7个皇后由于在第7列找不到合适的位置而无法被移动,那么算法就必须去掉它然后回溯到第6列的皇后。

最终算法不断重复着摆放皇后和回溯的过程直到找到问题的解为止。

下面给出了求解八皇后问题的示例程序。

#include <conio.h>#include <iostream>using namespace std;// 首先要求皇后不冲突,那么每行只应该有一个皇后// 用queens[]数组在存储每个皇后的位置// 例如: queens[m] = n 表示第m行的皇后放在第n列上#define MAX 8int sum = 0;class QueenPuzzle{int queens[MAX]; // 存储每行皇后的列标public:void printOut(); // 打印结果int IsValid(int n); //判断第n个皇后放上去之后,是否合法 void placeQueen(int i); // 递归算法放置皇后};void QueenPuzzle::printOut(){for(int i=0; i<MAX; i++){for(int j=0; j<MAX; j++){if(j == queens[i])cout << "Q ";elsecout << "0 ";}cout << endl;}cout << endl << "按q键盘退出,按其他键继续" << endl << endl;if(getch() == 'q')exit(0);}// 在第i行放置皇后void QueenPuzzle::placeQueen(int i){for(int j=0; j<MAX; j++){// 如果全部放完了输出结果if(i == MAX){sum ++;cout << "第" << sum << "组解:" << endl;printOut();return;}// 放置皇后queens[i] = j;// 此位置不能放皇后继续试验下一位置if(IsValid(i))placeQueen(i+1);}}//判断第n个皇后放上去之后,是否合法,即是否无冲突int QueenPuzzle::IsValid(int n){//将第n个皇后的位置依次于前面n-1个皇后的位置比较。

八皇后的递归和非递归的解法(C++)

八皇后的递归和非递归的解法(C++)

八皇后的递归和非递归的解法(C++)八皇后的递归和非递归的解法(C++)//描述:用递归和非递归模拟n皇后问题//输入:问题的规模:n//输出:皇后放置的方法排列和总数#include<iostream>#include<iomanip>#include<cmath>#include<stack>using namespace std;//利用递归求解皇后问题 x[i]表示皇后放在第i行第x[i]列static int count;//判断如果皇后放在第i行,第j列是否与前面的皇后冲突bool place(int i,int j,int* path)//path存放路径{int row;for(row=0;row<i;row++){if(abs(row-i)==abs(path[row]-j))//在同一条斜线上return false;if(j==path[row])//在同一列return false;}return true;}//利用递归来求解,而且当row==0时,即求解全局的解//path[n]用来存放路径void queen(int row,int* path,int n)if(row==n){//输出结果,并将办法数加1for(int i=0;i<n;i++){cout<<setw(5)<<left<<path[i];}cout<<endl;count++;}else{int j;//表示当前列是否可行for(j=0;j<n;j++){//如果可行,则放置并且递归调用处理下一行if(place(row,j,path)){path[row]=j;//这里相当于入栈的过程queen(row+1,path,n);}}}}//利用迭代来求解void queen_another(int n,int* path) {int i=0;for(i=0;i<n;i++){int j=0;for(;j<n;j++){if(place(i,j,path)){path[i]=j;cout<<"row "<<i<<"col "<<j<<endl; break;}}//没有合适的位置,所以要回溯到上一个最合适的节点if(j==n){i--;while(i>=0){int k=path[i]+1;while(k<n&&!(place(i,k,path)))k++;if(k==n)i--;else{path[i]=k;break;}if(i<0){cout<<"there is no way "<<endl;return;}}}if(i==n)for(int j=0;j<n;j++){cout<<setw(5)<<left<<path[j];path[j]=-1000;}}//利用栈来模拟递归,在某个扩展节点出处,将所有符合条件的节点加入到里面struct pos{int row;int col;};//找到当前最合适的节点,如果没有找到则返回-1int find_col(int row,int col,int* path,int n){int j;for(j=col;j<n;j++){if(place(row,j,path))return j;if(j==n)return -1;}//利用栈来模拟八皇后问题void stack_stimu(int n,int* path){stack<struct pos> s;int currow=0;int flag=0;//主要结构分为两部分,第一按照正常顺序寻找节点//然后找出回溯的情况:在八皇后问题中主要有两中:1.到达结尾找出路径 2.当前行没有满足条件的位置while(true){if(currow<n){int col=find_col(currow,0,path,n);if(col!=-1){pos node;node.row=currow;node.col=col;s.push(node);path[currow]=col;currow++;}elseflag=1;}else{for(int i=0;i<n;i++)cout<<setw(5)<<left<<path[i];cout<<endl;count++;flag=1;}// 进行回溯if(flag==1){//描述了回溯的过程while(!s.empty()){pos temp=s.top();if(temp.col!=7){//查找当前最适合的节点,并入栈int j=find_col(temp.row,temp.col+1,path,n); if(j!=-1){pos node;node.row=temp.row;node.col=j;s.pop();s.push(node);path[temp.row]=j;currow=temp.row+1;flag=0;break;}elses.pop();}elses.pop();}if(s.empty())return;//函数的出口处}}//end for while(true)}int main(){cout<<"Queen Place Problem:"<<endl; cout<<"Input the value of n"<<endl; int n;cout<<" n>";cin>>n;int* path=new int[n];//初始化for(int i=0;i<n;i++)path[i]=-1000;//queen_another(n,path);//queen(0,path,n);stack_stimu(n,path);cout<<"the count is: "<<count<<endl; getchar();getchar(); return 0; }。

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