八皇后之递归算法、回溯算法、穷举算法

合集下载

八皇后解题思路

八皇后解题思路

1.引子中国有一句古话,叫做“不撞南墙不回头",生动的说明了一个人的固执,有点贬义,但是在软件编程中,这种思路确是一种解决问题最简单的算法,它通过一种类似于蛮干的思路,一步一步地往前走,每走一步都更靠近目标结果一些,直到遇到障碍物,我们才考虑往回走。

然后再继续尝试向前。

通过这样的波浪式前进方法,最终达到目的地。

当然整个过程需要很多往返,这样的前进方式,效率比较低下。

2.适用范围适用于那些不存在简明的数学模型以阐明问题的本质,或者存在数学模型,但是难于实现的问题。

3.应用场景在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。

国际象棋的棋盘如下图所示:4.分析基本思路如上面分析一致,我们采用逐步试探的方式,先从一个方向往前走,能进则进,不能进则退,尝试另外的路径。

首先我们来分析一下国际象棋的规则,这些规则能够限制我们的前进,也就是我们前进途中的障碍物。

一个皇后q(x,y)能被满足以下条件的皇后q(row,col)吃掉1)x=row(在纵向不能有两个皇后)2) y=col(横向)3)col + row = y+x;(斜向正方向)4) col - row = y-x;(斜向反方向)遇到上述问题之一的时候,说明我们已经遇到了障碍,不能继续向前了。

我们需要退回来,尝试其他路径。

我们将棋盘看作是一个8*8的数组,这样可以使用一种蛮干的思路去解决这个问题,这样我们就是在8*8=64个格子中取出8个的组合,C(64,80) = 4426165368,显然这个数非常大,在蛮干的基础上我们可以增加回溯,从第0列开始,我们逐列进行,从第0行到第7行找到一个不受任何已经现有皇后攻击的位置,而第五列,我们会发现找不到皇后的安全位置了,前面四列的摆放如下:第五列的时候,摆放任何行都会上图所示已经存在的皇后的攻击,这时候我们认为我们撞了南墙了,是回头的时候了,我们后退一列,将原来摆放在第四列的皇后(3,4)拿走,从(3,4)这个位置开始,我们再第四列中寻找下一个安全位置为(7,4),再继续到第五列,发现第五列仍然没有安全位置,回溯到第四列,此时第四列也是一个死胡同了,我们再回溯到第三列,这样前进几步,回退一步,最终直到在第8列上找到一个安全位置(成功)或者第一列已经是死胡同,但是第8列仍然没有找到安全位置为止总结一下,用回溯的方法解决8皇后问题的步骤为:1)从第一列开始,为皇后找到安全位置,然后跳到下一列2)如果在第n列出现死胡同,如果该列为第一列,棋局失败,否则后退到上一列,在进行回溯3)如果在第8列上找到了安全位置,则棋局成功。

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

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

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

八皇后问题详细的解法

八皇后问题详细的解法

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

八皇后问题

八皇后问题

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

该问题是十九世纪著名的数学家高斯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) ;返回存储区域所需字节数。

算法入门经典-第七章例题7-2八皇后问题

算法入门经典-第七章例题7-2八皇后问题

算法⼊门经典-第七章例题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;}。

棋盘问题回溯求解算法

棋盘问题回溯求解算法

棋盘问题回溯求解算法1. 引言回溯法是一种用于解决组合问题的算法,它通过尝试所有可能的解决方案来找到满足特定条件的解。

棋盘问题是一类经典的组合问题,其目标是在一个棋盘上放置特定数量的棋子,使得它们满足一定的规则。

本文将介绍如何使用回溯法来求解棋盘问题。

2. 棋盘问题的定义棋盘问题通常是指在一个正方形棋盘上放置特定数量的棋子,使得它们满足特定规则。

常见的棋盘问题有八皇后问题、马踏棋盘问题等。

以八皇后问题为例,其规则是:在一个8x8的棋盘上放置8个皇后,使得每个皇后都不会互相攻击。

皇后可以攻击同一行、同一列或同一对角线上的其他皇后。

3. 回溯法求解棋盘问题回溯法是一种递归的搜索算法,它通过尝试所有可能的选择来找到满足条件的解。

具体步骤如下:1.定义一个数据结构来表示当前状态,例如使用一个数组来表示棋盘的布局。

2.从问题的起始状态开始,尝试所有可能的选择。

对于每一个选择,判断是否满足问题的约束条件。

3.如果当前选择满足约束条件,则将其添加到解空间中,并继续递归地探索下一个状态。

4.如果当前选择不满足约束条件,则回溯到上一个状态,并尝试下一个选择。

5.当所有的选择都被尝试完毕,或者已经找到了满足条件的解时,结束搜索。

4. 八皇后问题的回溯求解算法八皇后问题是一种经典的棋盘问题,其目标是在一个8x8的棋盘上放置8个皇后,使得它们互相之间不会攻击。

以下是八皇后问题的回溯求解算法:def solve_n_queens(n):result = []board = [['.' for _ in range(n)] for _ in range(n)]def is_valid(board, row, col):# 检查同一列是否有其他皇后for i in range(row):if board[i][col] == 'Q':return False# 检查左上方是否有其他皇后i, j = row - 1, col - 1while i >= 0 and j >= 0:if board[i][j] == 'Q':return Falsei -= 1j -= 1# 检查右上方是否有其他皇后i, j = row - 1, col + 1while i >= 0 and j < n:if board[i][j] == 'Q':return Falsei -= 1j += 1return Truedef backtrack(board, row):if row == n:result.append([''.join(row) for row in board])returnfor col in range(n):if is_valid(board, row, col):board[row][col] = 'Q'backtrack(board, row + 1)board[row][col] = '.'backtrack(board, 0)return result以上代码中,solve_n_queens函数接受一个整数n作为参数,表示棋盘的大小。

回溯法解决8皇后问题实验报告

回溯法解决8皇后问题实验报告

算法设计与分析实验报告实验名称:用回溯法解决八皇后问题姓名:学号:江苏科技大学一、实验名称:回溯法求解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皇后问题的计算,将结果存入数组。

八皇后问题实验报告

八皇后问题实验报告

软件工程上机报告实验名称:八皇后问题图形界面求解姓名:郭恂学号:2011011435班级:11级数学班中国石油大学(北京)计算机科学与技术系一、试验程序截图:点击显示下一组解即可显示下一组解:同样的,如果点击上一组解即可显示上一组解。

若在第1组解时点击显示上一组解会弹出报错提示框。

同样,若在第92组解点击显示下一组解也会弹出报错提示框:二、程序代码程序使用Java语言编写,编写环境为jdk1.6.0_18。

使用编程开发环境eclipse.exe编写。

本程序创建了两个类,两个类在同一个工程中。

其中Queen类的作用仅仅用来保存八皇后问题计算结果的数据,便于画图时使用。

本程序大概由两部分组成,第一部分是解八皇后问题,第二部分是画图。

程序源代码为:类1:public class Queen{public int[] x=new int[8];public int[] y=new int[8];public String name;}类2:import javax.swing.*;import java.awt.event.*;import java.awt.*;import javax.swing.JOptionPane;public class bahuanghou extends JFrame implements ActionListener {//JLabel[] l;int number=0; //当前显示的解的编号int sum=0; //所有解得数量JLabel l2;JButton b1,b2; //b1为显示下一组解得按钮,b2为显示上一组解得按钮。

Queen[] q=new Queen[128]; //得到的解储存在Queen类的数组里面。

private Image bomb1=Toolkit.getDefaultToolkit().getImage("D:\\qizi1.JPG"); //黑格棋子为bomb1private Image bomb2=Toolkit.getDefaultToolkit().getImage("D:\\qizi2.JPG"); //白格棋子为bomb2public bahuanghou() //构造方法,初始化窗口。

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

VAR
CONT,I:INTEGER;
A:ARRAY[1..N] OF BYTE;{存放正确的一组解}
C:ARRAY[1..N] OF BOOLEAN;{存放某一列放皇后的情况,用于判断是否有同列的情况}
L:ARRAY[1-N..N-1] OF BOOLEAN;{存放某一斜线上放皇后的情况,用于判断是否有同斜线的情况;斜线的方向为\}
R:ARRAY[2..2*N] OF BOOLEAN;{存放某一斜线上放皇后的情况,用于判断是否有同斜线的情况;斜线的方向为/}
PROCEDURE PR;
VAR
I:INTEGER;
BEGIN
FOR I:=1 TO N DO WRITE(A[I]:4);
INC(CONT);
WRITELN(' CONT=',CONT);
END;
PROCEDURE TRY(I:INTEGER);
VAR
J:INTEGER;
PROCEDURE ERASE(I:INTEGER);
BEGIN
C[J]:=TRUE;
L[I-J]:=TRUE;
R[I+J]:=TRUE;
END;
BEGIN
FOR J:=1 TO N DO
IF C[J] AND L[I-J] AND R[I+J] THEN
BEGIN
A[I]:=J;
C[J]:=FALSE;
L[I-J]:=FALSE;
R[I+J]:=FALSE;
IF I<N THEN TRY(I+1) ELSE PR;
ERASE(I);
END;
END;
END;
BEGIN
FOR I:=1 TO N DO C[I]:=TRUE;
FOR I:=1-N TO N-1 DO L[I]:=TRUE;
FOR I:=2 TO 2*N DO R[I]:=TRUE;
CONT:=0;
I:=1;
TRY(I);
WRITELN;
WRITELN('PROGRAM END.');
READLN;
END.
PROGRAM HUANGHOU(INPUT,OUTPUT);{回溯算法} CONST N=8;
VAR
K:INTEGER;
X:ARRAY[1..N] OF INTEGER;
FUNCTION PLACE(K:INTEGER):BOOLEAN;
VAR
I:INTEGER;
BEGIN
I:=1;
WHILE I<K DO
BEGIN
IF (ABS(X[I]-X[K])=ABS(I-K)) OR (X[I]=X[K]) THEN BEGIN
PLACE:=FALSE;
EXIT;
END;
I:=I+1;
END;
PLACE:=TRUE;
END;
PROCEDURE PRN;
VAR
I:INTEGER;
BEGIN
FOR I:=1 TO N DO WRITE(X[I]:4);
WRITELN;
END;
PROCEDURE NQUEENS(N:INTEGER);
BEGIN
X[1]:=0;
K:=1;
WHILE K>0 DO
BEGIN
X[K]:=X[K]+1;
WHILE ((X[K]<=N) AND (NOT PLACE(K))) DO X[K]:=X[K]+1;
IF X[K]<=N THEN
BEGIN
IF K=N THEN PRN
ELSE
BEGIN
K:=K+1;
X[K]:=0;
END;
END
ELSE K:=K-1;
END;
END;
BEGIN
NQUEENS(N);
READLN;
END.
PROGRAM BHH(INPUT,OUTPUT);{穷举算法:最好理解,但效率最低} CONST N=8;
VAR
I1,I2,I3,I4,I5,I6,I7,I8:INTEGER;
X:ARRAY [1..N] OF INTEGER;
PROCEDURE PRINT;{输出正确的解}
VAR
I:INTEGER;
BEGIN
WRITELN;
END;
FUNCTION CHECK():BOOLEAN;
VAR
A,B:INTEGER;
BEGIN
FOR A:=2 TO N DO
BEGIN
FOR B:=1 TO A-1 DO
BEGIN
IF (ABS(X[A]-X[B])=ABS(A-B)) OR (X[A]=X[B]) THEN
BEGIN
CHECK:=FALSE;
EXIT;
END;
END;
END;
CHECK:=TRUE;
END;
BEGIN
FOR I1:=1 TO N DO
FOR I2:=1 TO N DO
FOR I3:=1 TO N DO
FOR I4:=1 TO N DO
FOR I5:=1 TO N DO
FOR I6:=1 TO N DO
FOR I7:=1 TO N DO
BEGIN
X[1]:=I1;
X[2]:=I2;
X[3]:=I3;
X[4]:=I4;
X[5]:=I5;
X[6]:=I6;
X[7]:=I7;
X[8]:=I8;
IF CHECK() THEN PRINT;
END;
READLN;
END.
算法处理录入:admin责任编辑:admin ∙上一篇算法处理:杨辉三角
∙下一篇算法处理:OI之动态规划
【字体:小大】【发表评论】【告诉好友】【打印此文】【关闭窗口】。

相关文档
最新文档