八皇后问题(回溯法)

合集下载

八皇后问题c语言代码讲解

八皇后问题c语言代码讲解

八皇后问题c语言代码讲解八皇后问题是一个经典的回溯算法问题,要求在一个8x8的棋盘上放置8个皇后,使得它们互不攻击,即任意两个皇后都不能在同一行、同一列或同一对角线上。

下面是一个使用C语言实现八皇后问题的代码示例:c.#include <stdio.h>。

#define N 8。

int board[N][N];// 检查当前位置是否安全。

int isSafe(int row, int col) {。

int i, j;// 检查当前列是否有皇后。

for (i = 0; i < row; i++) {。

if (board[i][col] == 1) {。

return 0;}。

}。

// 检查左上对角线是否有皇后。

for (i = row, j = col; i >= 0 && j >= 0; i--, j--) {。

if (board[i][j] == 1) {。

return 0;}。

}。

// 检查右上对角线是否有皇后。

for (i = row, j = col; i >= 0 && j < N; i--, j++) {。

if (board[i][j] == 1) {。

return 0;}。

}。

return 1;}。

// 在当前行放置皇后。

int solve(int row) {。

int col;// 所有行都放置完毕,打印结果。

if (row == N) {。

for (int i = 0; i < N; i++) {。

for (int j = 0; j < N; j++) {。

printf("%d ", board[i][j]); }。

printf("\n");}。

printf("\n");return 1;}。

// 逐列尝试放置皇后。

for (col = 0; col < N; col++) {。

八皇后问题

八皇后问题

八皇后问题:在国际象棋里面皇后可以横走,竖走,斜走。

我们现在有一个8*8的棋盘,怎样摆放8个皇后,而使彼此不冲突,也就是怎样使在同一行,同一列,斜对角线上只存在一个皇后。

解决办法:回溯法回溯法:回溯法有“通用的解题法”之称。

应用回溯法解问题时,首先应该明确问题的解空间。

一个复杂问题的解决往往由多部分构成,即,一个大的解决方案可以看作是由若干个小的决策组成。

很多时候它们构成一个决策序列。

解决一个问题的所有可能的决策序列构成该问题的解空间。

解空间中满足约束条件的决策序列称为可行解。

一般说来,解任何问题都有一个目标,在约束条件下使目标值达到最大(或最小)的可行解称为该问题的最优解。

在解空间中,前k 项决策已经取定的所有决策序列之集称为k 定子解空间。

0 定子解空间即是该问题的解空间。

C语言代码:#include<stdio.h>int count=0;/*计数*/int fit(int (*Q)[8],int i,int j)/*判断是否适合摆放皇后*/{int t,e;for(t=i,e=0;e<8;e++)if(Q[t][e]==1&&e!=j) return 0;/*pan duan hang*/for(e=j,t=0;t<8;t++)if(Q[t][e]==1&&t!=i) return 0 ;/*pan duan lie*/for(e=j,t=i;e>0&&t>0;e--,t--)/*pan duan left up */if(Q[t][e]==1) return 0;for(e=j,t=i;e<8&&t<8;e++,t++)if(Q[t][e]==1) return 0; /*pan duan right down*/for(e=j,t=i;e<8&&t>0;e++,t--)if(Q[t][e]==1) return 0;/*pan duan right up*/for(e=j,t=i;e>0&&t<8;e--,t++)if(Q[t][e]==1) return 0;/*pan duan left down*/return 1;/*if all the conditions are the wrong ,then we will get 1 ,so the queenfunction will be told to make the Q[i][j]=1.we will put a queen on Q[i][j].*/}void queen(int (*Q)[8],int j)/*求8皇后问题的解*/{ int i,k;if(j==8)/*递归判断,当j=8,说明Q【】【7】中摆放了皇后,所以得到一个解*/{for(i=0;i<8;i++){for(k=0;k<8;k++)printf(" %d",Q[i][k]);/*统计摆放的种类,以及输出结果;*/printf("\n");}printf("\n");count++;return;}for(i=0;i<8;i++){if(fit(Q,i,j)>0)/*在生成解空间树的同时进行深度搜索,从而实现减枝*/{Q[i][j]=1;queen(Q,j+1);Q[i][j]=0;/*进行回溯,因为每次会形成不同的基点,然后沿着各基点进行深度搜索,所以每次搜索完要回到例外基点,所以前面搜索的基点必然要归为零*/}}}main(){int Q[8][8],i,j;for(i=0;i<8;i++)for(j=0;j<8;j++)Q[i][j]=0;queen(Q,0);printf("%d",count);}运行的部分结果:。

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

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

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

八皇后问题

八皇后问题

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

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

高斯认为有76种方案。

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

计算机发明后,有多种方法可以解决此问题。

八皇后问题最早是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。

之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。

八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。

诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。

1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。

艾兹格·迪杰斯特拉在1972年用这个问题为例来说明他所谓结构性编程的能力。

八皇后问题在1990年代初期的著名电子游戏第七访客和NDS平台的著名电子游戏雷顿教授与不可思议的小镇中都有出现。

2名词解释算法介绍八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。

八皇后问题可以推广为更一般的n 皇后摆放问题:这时棋盘的大小变为n ×n ,而皇后个数也变成n 。

当且仅当 n = 1 或 n ≥ 4时问题有解。

C 语言1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 intn=8;intx[9];intnum = 0;//解的个数//判断第k 个皇后能否放在第x[k]列boolPlace(intk){inti = 1;while ( i < k){if ( x[i]==x[k] || (abs (x[i]-x[k]) ==abs (i-k)) )returnfalse ;i++;}returntrue ;}void nQueens(intn){x[0] = x[1] =0;intk=1;while (k > 0){x[k]+=1;//转到下一行while (x[k]<=n && Place(k)==false ){//如果无解,最后一个皇后就会安排到格子外面去 x[k]+=1;}if (x[k]<=n){//第k 个皇后仍被放置在格子内,有解if (k==n){num++;cout << num <<":\t";for (inti=1; i<=n; i++){28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 cout << x[i] <<"\t";}cout << endl;}else {k++;x[k]=0;//转到下一行}}else //第k 个皇后已经被放置到格子外了,没解,回溯k--;//回溯}}int_tmain(intargc, _TCHAR* argv[]){nQueens(n);getchar ();return 0;}Java 算法1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 publicclass Queen {// 同栏是否有皇后,1表示有privateint [] column;// 右上至左下是否有皇后privateint [] rup;// 左上至右下是否有皇后privateint [] lup;// 解答privateint [] queen;// 解答编号privateint num;public Queen() {column =newint [8+1];rup =newint [2*8+1];lup =newint [2*8+1];for (int i =1; i <=8; i++)column[i] =1;2223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 for(int i =1; i <=2*8; i++)rup[i] = lup[i] =1;queen =newint[8+1];}publicvoid backtrack(int i) {if(i >8) {showAnswer();}else{for(int j =1; j <=8; j++) {if(column[j] ==1&&rup[i+j] ==1&&lup[i-j+8] ==1) {queen[i] = j;// 设定为占用column[j] = rup[i+j] = lup[i-j+8] =0; backtrack(i+1);column[j] = rup[i+j] = lup[i-j+8] =1; }}}}protectedvoid showAnswer() {num++;System.out.println("\n解答 "+ num);for(int y =1; y <=8; y++) {for(int x =1; x <=8; x++) {if(queen[y] == x) {System.out.print(" Q");}else{System.out.print(" .");}}System.out.println();}}publicstaticvoid main(String[] args) {Queen queen =new Queen();queen.backtrack(1);66 67 }}Erlang 算法-module(queen).-export([printf/0,attack_range/2]).-define(MaxQueen, 4).%寻找字符串所有可能的排列%perms([]) ->%[[]];%perms(L) ->% [[H | T] || H <- L, T <-perms(L -- [H])].perms([]) ->[[]];perms(L)->[[H | T] || H <- L, T <- perms(L -- [H]),attack_range(H,T) == []].printf() ->L =lists:seq(1, ?MaxQueen),io:format("~p~n",[?MaxQueen]),perms(L).%检测出第一行的数字攻击到之后各行哪些数字%left 向下行的左侧检测%right 向下行的右侧检测attack_range(Queen,List) ->attack_range(Queen,left, List) ++ attack_range(Queen,right, List).attack_range(_, _, [])->[];attack_range(Queen, left, [H | _]) whenQueen - 1 =:= H ->[H];attack_range(Queen,right, [H | _]) when Queen + 1 =:= H->[H];attack_range(Queen, left, [_ | T])->attack_range(Queen - 1, left,T);attack_range(Queen, right, [_ | T])->attack_range(Queen + 1, right, T).C 语言算法C 代码头文件1 2 3 4 5 6 7 8 9 10 11 //eigqueprob.h#include#define N 8 /* N 表示皇后的个数 *//* 用来定义答案的结构体*/typedefstruct {intline;/* 答案的行号 */introw;/* 答案的列号 */}ANSWER_TYPE;/* 用来定义某个位置是否被占用 */12 13 14 15 16 17 18 19 20 typedefenum {notoccued = 0,/* 没被占用 */occued = 1/* 被占用 */}IFOCCUED; /* 该列是否已经有其他皇后占用 */IFOCCUED rowoccu[N];/* 左上-右下对角位置已经有其他皇后占用 */IFOCCUED LeftTop_RightDown[2*N-1];/* 右上-左下对角位置已经有其他皇后占用*/IFOCCUED RightTop_LefttDown[2*N-1];/* 最后的答案记录 */ANSWER_TYPE answer[N];主程序1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include "eigqueprob.h"/* 寻找下一行占用的位置 */void nextline(intLineIndex){static asnnum = 0;/* 统计答案的个数 */intRowIndex = 0;/* 列索引 */intPrintIndex = 0;/* 按列开始遍历 */for (RowIndex=0;RowIndex{/* 如果列和两个对角线上都没有被占用的话,则占用该位置 */if ((notoccued == rowoccu[RowIndex])\&&(notoccued == LeftTop_RightDown[LineIndex-RowIndex+N-1])\&&(notoccued == RightTop_LefttDown[LineIndex+RowIndex])){/* 标记已占用 */rowoccu[RowIndex] = occued;LeftTop_RightDown[LineIndex-RowIndex+N-1] = occued;RightTop_LefttDown[LineIndex+RowIndex] = occued;/* 标记被占用的行、列号 */answer[LineIndex].line = LineIndex;answer[LineIndex].row = RowIndex;/* 如果不是最后一行,继续找下一行可以占用的位置 */if ((N-1) > LineIndex ){nextline(LineIndex+1);}/* 如果已经到了最后一行,输出结果 */else{asnnum++;printf ("\nThe %dth answer is :",asnnum);for (PrintIndex=0;PrintIndex{343536373839404142434445464748495051525354 printf("(%d,%d) ",answer[PrintIndex].line+1,answer[PrintIndex].row+1}/* 每10个答案一组,与其他组隔两行 */if((asnnum % 10) == 0)printf("\n\n");}/* 清空占用标志,寻找下一组解 */rowoccu[RowIndex] = notoccued;LeftTop_RightDown[LineIndex-RowIndex+N-1] = notoccued;RightTop_LefttDown[LineIndex+RowIndex] = notoccued;}}}main(){inti = 0;/* 调用求解函数*/nextline(i);/* 保持屏幕结果*/getchar();}C语言实现图形实现对于八皇后问题的实现,如果结合动态的图形演示,则可以使算法的描述更形象、更生动,使教学能产生良好的效果。

数据结构与算法中的“递归”——用回溯法求解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皇后问题分析

八皇后以及N皇后问题分析

⼋皇后以及N皇后问题分析⼋皇后是⼀个经典问题,在8*8的棋盘上放置8个皇后,每⼀⾏不能互相攻击。

因此拓展出 N皇后问题。

下⾯慢慢了解解决这些问题的⽅法:回溯法:回溯算法也叫试探法,它是⼀种系统地搜索问题的解的⽅法。

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

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

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

N皇后问题在N增⼤时就是这样⼀个解空间很⼤的问题,所以⽐较适合⽤这种⽅法求解。

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

算法描述:1. 算法开始,清空棋盘。

当前⾏设为第⼀⾏,当前列设为第⼀列。

2. 在当前⾏,当前列的判断放置皇后是否安全,若不安全,则跳到第四步。

3. 在当前位置上满⾜条件的情况: 在当前位置放⼀个皇后,若当前⾏是最后⼀⾏,记录⼀个解; 若当前⾏不是最后⼀⾏,当前⾏设为下⼀⾏,当前列设为当前⾏的第⼀个待测位置; 若当前⾏是最后⼀⾏,当前列不是最后⼀列,当前列设为下⼀列; 若当前⾏是最后⼀⾏,当前列是最后⼀列,回溯,即清空当前⾏以及以下各⾏的棋盘,然后当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置; 以上返回第⼆步。

4.在当前位置上不满⾜条件: 若当前列不是最后⼀列,当前列设为下⼀列,返回到第⼆步; 若当前列是最后⼀列,回溯,即,若当前⾏已经是第⼀⾏了,算法退出,否则,清空当前⾏以及以下各⾏的棋盘,然后,当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置,返回第⼆步。

如何判断是否安全:把棋盘存储为⼀个N维数组a[N],数组中第i个元素的值代表第i⾏的皇后位置,这样便可以把问题的空间规模压缩为⼀维O(N),在判断是否冲突时也很简单, ⾸先每⾏只有⼀个皇后,且在数组中只占据⼀个元素的位置,⾏冲突就不存在了, 其次是列冲突,判断⼀下是否有a[i]与当前要放置皇后的列j相等即可。

八皇后问题——回溯法(pythonJAVA)

⼋皇后问题——回溯法(pythonJAVA)⼋皇后问题,是⼀个古⽼⽽著名的问题,问题如下:在8×8格的国际象棋上摆放⼋个皇后,使其不能互相攻击,即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上,问有多少种摆法。

上边是⼀个8*8的国际棋盘,可以看到棋盘中的每个格⼦都标有数字。

每个数字都是两位,⼗位数字表⽰该格⼦所在的⾏,⽽个位数字表⽰该格⼦所在的列。

这样不难发现,处在同⼀⾏的两个格⼦其⼗位数都相同,处在同⼀列的两个格⼦其个位数都相同,处在同⼀斜线的两个格⼦有:|两个数字个位数的差|=|两个数字⼗位数的差|。

主要的三个限制条件明⽩了,接下来我们选择⼀种数据结构对“皇后”进⾏存储。

很明显,我们可以选择⼆维数组。

但是还可以选择⼀维数组。

在这⾥我们选择⼀维数组。

为什么选择⼀维数组呢?1.因为⼀⾏只放⼀个皇后,很符合我们⼀维数组的存放特性,即⼀个索引对应⼀个元素。

2.相对于⼆维数组,⼀位数组⽐较简单,更适合初学者。

我们以皇后所在的⾏标作为⼀位数组的索引,皇后所在的列标作为该索引对应的元素,例如arr[3]=5,代表第三⾏的皇后在第五列。

下边我们以python以及JAVA为例来解决这个问题。

num=0def eight_queen(arr,finish_line=0):if finish_line == len(arr): #如果放置皇后成功的⾏数与数组中的元素个数⼀致(即棋盘的⾏数)则认为完成了⼀种摆法global num #将上边定义的num定义为全局变量这样才能在后边对其进⾏⾃加操作num+=1print("第%s种摆法:" % num)for i in range(8):print((i,arr[i]))return# breakfor stand in range(len(arr)): #对整个列进⾏扫描,将列标的标号赋值给数组中对应的元素arr[finish_line] = standflag = Truefor line in range(finish_line):if arr[line] == stand or abs(arr[line]-stand) == finish_line-line: #有皇后与当前放置的皇后处于同⼀列或同⼀斜线上flag = False# stand-=1if flag==True:eight_queen(arr,finish_line+1)if__name__ == '__main__':eight_queen([None]*8)if num != 0:print("⼀共有%s种摆法" % num)else:print("⽆解")对于初学者理解可能不是特别轻松,所以在这⾥我们总结⼀个的定式,再遇到此类问题时直接套⽤以下定式即可。

数据结构课程设计 回溯法解决8皇后n皇后问题

数据结构课程设计学院:信息科学技术学院专业:电子信息工程(1)姓名:谢后乐学号:20101601310015N皇后问题N皇后问题:在n×n格的棋盘上放置彼此不受攻击的n个皇后。

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上。

回溯法简介:回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。

但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

我们发现,对于许多问题,所给定的约束集D具有完备性,即i元祖(x1,x2,…,xi)满足D中仅涉及到x1,x2,…,xi的所有约束意味着j(j<=i)元组(x1,x2,…)一定也满足D中仅涉及到x1,x2,…,的所有约束,i=1,2,…,n。

换句话说,只要存在0≤j≤n-1,使得(x1,x2,…,)违反D中仅涉及到x1,x2,…,的约束之一,则以(x1,x2,…,)为前缀的任何n元组(x1,x2,…,j+1,…,)一定也违反D中仅涉及到x1,x2,…,xi的一个约束,n≥i≥j。

因此,对于约束集D具有完备性的问题P,一旦检测断定某个j元组(x1,x2,…)违反D中仅涉及x1,x2,…,的一个约束,就可以肯定,以(x1,x2,…)为前缀的任何n元组(x1,x2,…,)都不会是问题P的解,因而就不必去搜索它们、检测它们。

回溯法正是针对这类问题,利用这类问题的上述性质而提出来的比枚举法效率更高的算法。

空间树回溯法首先将问题P的n元组的状态空间E表示成一棵高为n的带权有序树T,把在E中求问题P的所有解转化为在T中搜索问题P的所有解。

树T类似于检索树,它可以这样构造:设Si中的元素可排成xi(1) ,xi(2) ,...,xi(mi-1) ,|Si| =mi,i=1,2,...,n。

4八皇后问题

实验四八皇后问题
一、目的和要求
1. 掌握递归的使用方法。

2. 掌握回溯法。

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

三、算法:
提示:
1.皇后q1(x1,y1)和皇后q2(x2,y2)相互吃掉的条件:
x1 == x2 || y1 == y2 || x1 – x2 == y1 – y2 || x1 – x2 == y2 – y1
2.用回溯法解决八皇后问题的步骤为:
用一个数组存储当前成功摆放的皇后位置,以便下一列摆放皇后时进行安全判断。

因为一列(行)只能摆放一个皇后,否则会互相吃掉,所以可以用列(行)号来作为递归函数的n
1)从第1列开始,为皇后找到安全位置,然后递归进行下一列。

2) 如果在第8列上找到了安全位置,则棋局成功,输出此种摆放下所有皇后的位置信息。

3) 如果在第n列出现死胡同(在所有位置都不能安全摆放皇后了),则后退到上一列进行回溯(如果用递归实现,该回溯是递归调用自动完成)。

程序请自行设计。

C语言回溯法解八皇后问题(八皇后算法)

C语⾔回溯法解⼋皇后问题(⼋皇后算法)⼋皇后问题(N皇后问题)的回溯法求解⼀、问题描述在⼀个国际象棋棋盘上放置⼋个皇后,使得任何两个皇后之间不相互攻击,求出所有的布棋⽅法,并推⼴到N皇后情况。

⼆、参考资料啥⽂字都不⽤看,B站上有个⾮常详细的动画视频解说,上链接三、源代码#include<iostream>#include<vector>#include<string>using namespace std;void put_queen(int x, int y, vector<vector<int>>&attack){//实现在(x,y)放置皇后,对attack数组更新,xy表⽰放置皇后的坐标,attack表⽰是否可以放置皇后//⽅向数组,⽅便后⾯对8个⽅向进⾏标记static const int dx[] = { -1,-1,-1,0,0,1,1,1 };static const int dy[] = { -1,0,1,-1,1,-1,0,1 };attack[x][y] = 1;//将皇后位置标记为1//通过两层for循环,将该皇后可能攻击到的位置标记for (int i = 1; i < attack.size(); i++)//从皇后位置向1到n-1个距离延伸{for (int j = 0; j < 8; j++)//遍历8个⽅向{int nx = x + i * dx[j];//⽣成的新位置⾏int ny = y + i * dy[j];//⽣成的新位置列//在棋盘范围内if (nx >= 0 && nx < attack.size() && ny >= 0 && ny < attack.size())attack[nx][ny] = 1;//标记为1}}}//回溯算法//k表⽰当前处理的⾏//n表⽰n皇后问题//queen存储皇后的位置//attack标记皇后的攻击范围//solve存储N皇后的全部解法void backtrack(int k, int n, vector<string>& queen,vector<vector<int>>& attack,vector<vector<string>>& solve){if (k == n)//找到⼀组解{solve.push_back(queen);//将结果queen存储⾄solvereturn;}//遍历0⾄n-1列,在循环中,回溯试探皇后可放置的位置for (int i = 0; i < n; i++){if (attack[k][i] == 0)//判断当前k⾏第i列是否可以放置皇后{vector<vector<int>> tmp = attack;//备份attack数组queen[k][i] = 'Q';//标记该位置为Qput_queen(k, i, attack);//更新attack数组backtrack(k + 1, n, queen, attack, solve);//递归试探k+1⾏的皇后的位置attack = tmp;//恢复attack数组queen[k][i] = '.';//恢复queen数组}}}vector<vector<string>>solveNQueens(int n){//string存储具体的摆放位置,<vector<string>>存放⼀种解法,⼆维vector存放全部解法vector<vector<string>>solve;//存储最后结果vector<vector<int>>attack;//标记皇后的攻击位vector<string>queen;//保存皇后位置//使⽤循环初始化attack和queen数组for (int i = 0; i < n; i++){attack.push_back((vector<int>()));for (int j = 0; j < n; j++){attack[i].push_back(0);}queen.push_back("");queen[i].append(n, '.');}backtrack(0, n, queen, attack, solve);return solve;//返回结果数组}int main(){//int num;//cin >> num;//输⼊皇后数初始化attack数组//vector<vector<int>> attack(num,vector<int>(num, 0));初始化queen数组//string s;//for (int i = 0; i < num; i++)s += '.';//vector<string> queen(num, s);int n;cin >> n;vector<vector<string>>result;result = solveNQueens(n);cout << n << "皇后共有" << result.size() << "种解法" << endl;for (int i = 0; i < result.size(); i++){cout << "解法" << i + 1 << ":" << endl;for (int j = 0; j < result[i].size(); j++){cout << result[i][j] << endl;}cout << endl;}system("pause");return 0;}四、测试结果四皇后⼋皇后到此这篇关于C语⾔回溯法解⼋皇后问题的⽂章就介绍到这了。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include <stdlib.h>
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]行处没有皇后(所在行,对角线,次对角线上都没有皇后)
}
col[m]++; //继续试探本列其他行
{
if(m==N) //已经找到一个解
{
printf("列\t\t行\n");
for(j=1;j<=N;j++)
{printf("%d\t\t%d\n",j,col[j]);}
printf("Enter a character(Q/q for exit)!\n");
scanf("%c",&awn);
return 0;
{
m--;
a[col[m]]=b[m+col[m]]=c[N+m-col[m]]=1;
}
col[m]++; //试探其它行
}
good=a[col[m]]&&b[m+col[m]]&&c[N+m-col[m]]; //检查是否满足要求
}while(m!=0);
}
int main()
{
queen(8);
}
Байду номын сангаасelse //当前放置的皇后满足要求,但还没找到解,继续考察下一列
{
a[col[m]]=b[m+col[m]]=c[N+m-col[m]]=0; //标志当前位置已经放置皇后
col[++m]=1; //转到下一列第一行
}
}
else
{
while(col[m]==N) //已经到了列底,所以回溯到上一列
为使在检查皇后配置的合理性方面简易方便,引入一下4个工作数组:
•数组col[i],表示在棋盘第i列,col[i]行有一个皇后;
•数组a[],a[k]表示第k行上还没有皇后;
•数组b[],b[k]表示第k列右高左低斜线上没有皇后;
•数组c[],c[k]表示第k列左高右低斜线上没有皇后;
代码:
#include <stdio.h>
相关文档
最新文档