算法实验 递归回溯解八皇后问题

合集下载

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

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

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

⼋皇后问题(经典算法-回溯法)问题描述:⼋皇后问题(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;}。

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

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

算法设计与分析实验报告—八皇后问题-姓名:***学号:********班级:软件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]列时是否与前面已放置好的皇后相攻击。

八皇后问题

八皇后问题

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

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

高斯认为有76种方案。

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

对于八皇后问题的实现,如果结合动态的图形演示,则可以使算法的描述更形象、更生动,使教学能产生良好的效果。

下面是用Turbo C实现的八皇后问题的图形程序,能够演示全部的92组解。

八皇后问题动态图形的实现,主要应解决以下两个问题。

(1)回溯算法的实现(a)为解决这个问题,我们把棋盘的横坐标定为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)的对角线(右上至左下)有皇后(b)为第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) ;返回存储区域所需字节数。

回溯算法与八皇后问题N皇后问题Word版

回溯算法与八皇后问题N皇后问题Word版

回溯算法与八皇后问题(N皇后问题)1 问题描述八皇后问题是数据结构与算法这一门课中经典的一个问题。

下面再来看一下这个问题的描述。

八皇后问题说的是在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。

更通用的描述就是有没有可能在一张N*N的棋盘上安全地放N个皇后?2 回溯算法回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。

回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。

在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满足某种要求的可能或最优的情况,从而得到整个问题的解。

回溯算法就是解决这种问题的“通用算法”,有“万能算法”之称。

N皇后问题在N增大时就是这样一个解空间很大的问题,所以比较适合用这种方法求解。

这也是N皇后问题的传统解法,很经典。

下面是算法的高级伪码描述,这里用一个N*N的矩阵来存储棋盘:1) 算法开始, 清空棋盘,当前行设为第一行,当前列设为第一列2) 在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步3) 在当前位置上满足条件的情形:在当前位置放一个皇后,若当前行是最后一行,记录一个解;若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;若当前行是最后一行,当前列不是最后一列,当前列设为下一列;若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;以上返回到第2步4) 在当前位置上不满足条件的情形:若当前列不是最后一列,当前列设为下一列,返回到第2步;若当前列是最后一列了,回溯,即,若当前行已经是第一行了,算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置,返回到第2步;算法的基本原理是上面这个样子,但不同的是用的数据结构不同,检查某个位置是否满足条件的方法也不同。

数据结构与算法中的“递归”——用回溯法求解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个皇后的位置比较。

八皇后问题详细的解法

八皇后问题详细的解法

若无法放下皇后则回到上一行, 即回溯
当n行的皇后都已确定后,我们 就找到了一种方案
17
check2 (int a[ ],int n)
queen21(例) 1 b加约束的枚举算法{//i多nt次i; 被调用,只是一重循环
{int a[9];
for(i=1;i<=n-1;i++)
for (a[1]=1;a[1]<=8;a[1]++)
{ if (i=n) 搜索到一个解,输出; //搜索到叶结点
else
//正在处理第i个元素
{a[i]第一个可能的值;
while (a[i]不满足约束条件且在搜索空间内)
a[i]下一个可能的值;
if (a[i]在搜索空间内)
{标识占用的资源; i=i+1;} //扩展下一个结点
else {清理所占的状态空间;i=i-1;} //回溯
按什么顺序去搜? 目标是没有漏网之鱼,尽量速度快。
5
2 【问题设计】盲目的枚举算法
a 盲目的枚举算法
通过8重循环模拟搜索空间中的88个状态;
按枚举思想,以DFS的方式,从第1个皇后在第1列开 始搜索,枚举出所有的“解状态”:
从中找出满足约束条件的“答案状态”。
约束条件?
题,而不能解决任意
}}}}}}}
的n皇后问题。
18
2 回溯法应用-算法说明
八皇后问题中的核心代码: 遍历过程函数; check函数。
解决此类问题的核心内容: 解空间树的搜索算法; 估值/判断函数:判断哪些状态适合继续扩展,或者作 为答案状态。
19
2 回溯法应用-n皇后问题
for(j=1;j<=i-1;j++)

八皇后问题递归算法

八皇后问题递归算法

八皇后问题递归算法八皇后问题是一个经典的数学问题,其目标是在一个8×8的棋盘上放置8个皇后,使得没有两个皇后位于同一行、同一列或同一斜线上。

这个问题可以通过递归算法来求解,本文将详细介绍八皇后问题的递归算法及其实现过程。

我们需要定义一个函数来判断当前位置是否可以放置皇后。

该函数的输入参数为当前行和当前列,输出为一个布尔值,表示该位置是否可以放置皇后。

具体实现如下:```bool isSafe(int board[8][8], int row, int col){int i, j;// 检查当前列是否有其他皇后for (i = 0; i < row; i++)if (board[i][col])return false;// 检查左上方是否有其他皇后for (i = row, j = col; i >= 0 && j >= 0; i--, j--)if (board[i][j])return false;// 检查右上方是否有其他皇后for (i = row, j = col; i >= 0 && j < 8; i--, j++)if (board[i][j])return false;return true;}```接下来,我们可以使用递归算法来解决八皇后问题。

递归算法的思想是将问题分解为子问题,然后逐步解决子问题,最终得到原问题的解。

具体的递归算法如下:```bool solveNQueens(int board[8][8], int row){// 所有行都已经放置好了皇后,得到了一个解if (row == 8)return true;// 尝试在当前行的每个列中放置皇后for (int col = 0; col < 8; col++)// 检查当前位置是否可以放置皇后if (isSafe(board, row, col)){// 放置皇后board[row][col] = 1;// 递归求解下一行if (solveNQueens(board, row + 1))return true;// 回溯,撤销当前位置的皇后board[row][col] = 0;}}// 无法找到解return false;}```我们可以编写一个主函数来调用递归算法并打印结果。

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

深圳大学实验报告
课程名称:算法分析与复杂性理论
实验项目名称:八皇后问题
学院:计算机与软件学院
专业:软件工程
指导教师:杨烜
报告人:学号:班级:15级软工学术型
实验时间:2015-12-08
实验报告提交时间:2015-12-09
教务部制
一.实验目的
1.掌握选回溯法设计思想。

2.掌握八皇后问题的回溯法解法。

二.实验步骤与结果
实验总体思路:
根据实验要求,通过switch选择八皇后求解模块以及测试数据模块操作,其中八皇后模块调用摆放皇后函数模块,摆放皇后模块中调用判断模块。

测试数据模块主要调用判断模块进行判断,完成测试。

用一维数组保存每行摆放皇后的位置,根据回溯法的思想递归讨论该行的列位置上能否放置皇后,由判断函数Judge()判断,若不能放置则检查该行下一个位置。

相应结果和过程如下所示(代码和结果如下图所示)。

回溯法的实现及实验结果:
1、判断函数
代码1:
procedure BTrack_Queen(n)
皇后问题 2.测试数据0.退出**"<<endl;
cout<<"******************************************"<<endl;
cin>>n;
switch(n){
case 0: cout<<"退出程序成功..."<<endl;
return 0; //一个程序两个出口
case 1: cout<<"八皇后问题的解为:"<<endl;
BackTrack_Queen(0);
cout<<"共有"<<sum<<"个解"<<endl;
break;
case 2: cout<<"运行测试数据:"<<endl;
while(1) {
cout<<"请输入要测试的数据:"<<endl;
for(int j=0;j<max;j++)
cin>>queen[j];
if(Judge(max)==1) cout<<"该数据是八皇后问题的解"<<endl;
else cout<<"该数据不是八皇后问题的解"<<endl;
}
break;
default: cout<<"输入非法,请重新输入!"<<endl;
}
}
return 0;
}
注:MFC实现代码下载:若链接无效可加我百度云好友:123望月台456。

相关文档
最新文档