八皇后问题(回溯法)
八皇后问题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皇后问题
八皇后问题是一个古老而著名的问题,它是回溯算法的典型例题。
该问题是十九世纪德国著名数学家高斯于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皇后问题分析⼋皇后是⼀个经典问题,在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语⾔回溯法解⼋皇后问题的⽂章就介绍到这了。
八皇后问题—经典回溯算法
⼋皇后问题—经典回溯算法⼋皇后问题⼋皇后问题,是⼀个古⽼⽽著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋⼿马克斯·贝瑟尔于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;}};。
八皇后
内容摘要八皇后问题是十九世纪著名数学家高斯于1850年提出的。
问题是:在8*8的棋盘上摆放8个皇后,使其不能互相攻击,即任意的两个皇后不能处在同意行,同一列,或同意斜线上。
可以把八皇后问题拓展为n皇后问题,即在n*n的棋盘上摆放n个皇后,使其任意两个皇后都不能处于同一行、同一列或同一斜线上。
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。
但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为"回溯点"。
关键词:八皇后问题;回溯法;探索;选优;试探法;目录1.引言 (1)1.1研究的缘起 (1)1.2本文的研究思路、方法及意义 (1)1.3相关理论基础 (1)2.实验过程分析 (1)2.1算法描述 (1)2.2实验工具 (1)3.结果与讨论 (1)3.1算法分析 (1)3.2研究与结论 (3)4.设计体会 (5)5.参考文献 (5)1.引言1.1研究的缘起在8X8格的国际象棋棋盘上放置8个皇后,使得任意两个皇后不能互相攻击,即任何行、列或对角线(与水平轴夹角为45°或135°的斜线)上不得有两个或两个以上的皇后。
这样的一个格局称为问题的一个解。
请用回溯算法写出求皇后问题的算法。
1.2本文的研究思路、方法及意义每一行可以而且必须放一个皇后,所以n皇后问题的解可以用一个n元向量X=(x1,x2,.....xn)表示,其中,1≤i≤n且1≤xi≤n,即第n个皇后放在第i行第xi列上。
由于两个皇后不能放在同一列上,所以,解向量X必须满足的约束条件为:xi≠xj;若两个皇后的摆放位置分别是(i,xi)和(j,xj),在棋盘上斜率为-1的斜线上,满足条件:i-j=xi-xj;在棋盘上斜率为1的斜线上,满足条件:i+j=xi+xj;综合两种情况,由于两个皇后不能位于同一斜线上,所以,解向量X必须满足的约束条件为:|i-xi|≠|j-xj|;显然,八皇后问题就可以根据解n皇后的这个思路去解决。
八皇后问题最简单算法
八皇后问题最简单算法
八皇后问题最简单算法是使用回溯法。
1. 回溯法在求解八皇后问题时,会生成一个8位的二进制数,每一位代表一列是否放置皇后。
如果某一列放置了皇后,则该位为1,否则为0。
2. 在放置皇后时,如果当前位置可以放置皇后,则尝试放置。
如果放置后当前位置形成了一个合法的棋盘,则继续递归地放置下一个皇后。
如果放置后形成了一个不合法的棋盘,则回溯到上一个状态,尝试其他位置。
3. 如果所有8个皇后都放置完毕,且形成了一个合法的棋盘,则找到了一个解。
以上信息仅供参考,如需了解更多信息,建议查阅八皇后问题相关书籍或咨询专业人士。
JS算法之八皇后问题(回溯法)
JS算法之⼋皇后问题(回溯法)⼋皇后这个经典的算法⽹上有很多种思路,我学习了之后⾃⼰实现了⼀下,现在⼤概说说我的思路给⼤家参考⼀下,也算记录⼀下,以免以后⾃⼰忘了要重新想⼀遍。
⼋皇后问题⼋皇后问题,是⼀个古⽼⽽著名的问题,是回溯算法的典型案例。
该问题是国际西洋棋棋⼿马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放⼋个皇后,使其不能互相攻击,即任意两个皇后都不能处于同⼀⾏、同⼀列或同⼀斜线上,问有多少种摆法。
⼯作原理⾸先从定义知道,两个皇后都不能处于同⼀⾏,所以第0个皇后放在第0⾏,第⼀个皇后放在第1⾏,以此类推。
先在第0⾏第0个格⼦(0,0)放⼀个皇后0,接着把处于同⼀⾏、同⼀列或同⼀斜线上的格⼦都标记为皇后0;然后把皇后1放到第1⾏标记为-1的格⼦中,以此类推直到放下皇后7(即最后⼀个皇后)。
若中途出现放皇后 iQueen时,第 iQueen⾏所有格⼦已经被全部标记,即if( arr[ iQueen*n + i ].index == -1 )的判断,则回溯到上⼀层函数(其实就是没有进⼊到if分⽀,所有没有进⾏递归了,代码执⾏完⾃然会跳回上⼀层函数继续执⾏)。
注意此时的执⾏环境(exection context)已经变了,所有setQueen函数内定义的变量全部回溯到上⼀层函数递归到下⼀层函数前的状态,即执⾏setQueen( iQueen + 1 );这⾏代码前的状态,例如递归前i=2,iQueen=1,⽆论下⼀层函数⾥的i和iQueen怎样变化,回溯后还是i=2,iQueen=1,然后紧接着执⾏未执⾏完的代码。
下⾯是执⾏顺序⼤概的图解:执⾏顺序:1.if-->1.1-->1.2-->1.递归-->2.if-->2.1-->2.2-->2.递归-->3.if-->2.回溯-->1.回溯(前⾯的标号表⽰第⼏层)var n = 8;//总⾏(列)数 8*8var iCount = 0;//n皇后的解法数//arr是长度为n*n的⼀维数组,保存着n*n个对象(li)并有各⾃的坐标,默认index都为-1,表⽰没有被任何皇后标记过 arr[ i*n + j ].y = i; arr[ i*n + j ].x = j;for(var i=0;i<n;i++){for(var j=0;j<n;j++){arr[ i*n + j ].x = j;arr[ i*n + j ].y = i;//arr[ i*n + j ].innerHTML = j + ',' + i;}}//iQueen从0开始,即皇后0function setQueen(iQueen){if( iQueen == n ){iCount++;console.log(iCount)return;}for(var i=0;i<n;i++){if( arr[ iQueen*n + i ].index == -1 ){arr[ iQueen*n + i ].index = iQueen;//arr[ iQueen*n + i ].innerHTML = iQueen;var x = arr[ iQueen*n + i ].x;var y = arr[ iQueen*n + i ].y;for(var j=0;j<arr.length;j++){if( arr[j].index == -1 && (arr[j].x == x || arr[j].y == y || arr[j].x - arr[j].y == x - y || arr[j].x + arr[j].y == x + y) ){arr[j].index = iQueen;//arr[j].innerHTML = iQueen;}}//执⾏到这⾥,就会跳到下⼀层函数中,在执⾏完下⼀层的函数后,才会回溯到上⼀层继续执⾏for循环(此时的for循环是上⼀层的for循环),包括后⾯的所有代码//需要注意的是,例如当前函数的iQueen=1,跳到下⼀层函数 iQueen=2,下⼀层函数执⾏完后,回溯到上⼀层,此时的执⾏环境已经是上⼀层的执⾏环境了,即iQueen是等于1,⽽不是等于2 //递归setQueen( iQueen + 1 );//回溯for(var j=0;j<arr.length;j++){if( arr[j].index == iQueen ){arr[j].index = -1;//arr[j].innerHTML = -1; }}}}}。
八皇后回溯算法的实现
回溯算法的实现(1)为解决这个问题,我们把棋盘的横坐标定为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)的对角线(右上至左下)有皇后(2)为第i个皇后选择位置的算法如下:for(j=1;j<=8;j++) /*第i个皇后在第j行*/if ((i,j)位置为空))/*即相应的三个数组的对应元素值为1*/{占用位置(i,j)/*置相应的三个数组对应的元素值为0*/if i<8为i+1个皇后选择合适的位置;else 输出一个解}#include <graphics.h>#include <stdlib.h>#include <stdio.h>#include <dos.h>char n[3]={'0','0'};/*用于记录第几组解*/int a[8],b[15],c[24],i;int h[8]={127,177,227,277,327,377,427,477};/*每个皇后的行坐标*/int l[8]={252,217,182,147,112,77,42,7};/*每个皇后的列坐标*/void *arrow;void try(int i){int j;for (j=1;j<=8;j++)if (a[j-1]+b[i+j-2]+c[i-j+7]==3) /*如果第i列第j行为空*/{a[j-1]=0;b[i+j-2]=0;c[i-j+7]=0;/*占用第i列第j行*/putimage(h[i-1],l[j-1],arrow,COPY_PUT);/*显示皇后图形*/delay(500);/*延时*/if(i<8) try(i+1);else /*输出一组解*/{n[1]++;if (n[1]>'9') {n[0]++;n[1]='0';}bar(260,300,390,340);/*显示第n组解*/outtextxy(275,300,n);delay(3000);}a[j-1]=1;b[i+j-2]=1;c[i-j+7]=1;putimage(h[i-1],l[j-1],arrow,XOR_PUT);/*消去皇后,继续寻找下一组解*/ delay(500);}}int main(void){int gdrive=DETECT,gmode,errorcode;unsigned int size;inITgraph(&gdrive,&gmode,"");errorcode=graphresult();if (errorcode!=grOk){printf("Graphics error\n");exIT(1);}rectangle(50,5,100,40);rectangle(60,25,90,33);/*画皇冠*/line(60,28,90,28);line(60,25,55,15);line(55,15,68,25);line(68,25,68,10);line(68,10,75,25);line(75,25,82,10);line(82,10,82,25);line(82,25,95,15);line(95,15,90,25);size=imagesize(52,7,98,38); arrow=malloc(size);getimage(52,7,98,38,arrow);/*把皇冠保存到缓冲区*/clearviewport();settextstyle(TRIPLEX_FONT, HORIZ_DIR, 4);setusercharsize(3, 1, 1, 1);setfillstyle(1,4);for (i=0;i<=7;i++) a[i]=1;for (i=0;i<=14;i++) b[i]=1;for (i=0;i<=23;i++) c[i]=1;for (i=0;i<=8;i++) line(125,i*35+5,525,i*35+5);/*画棋盘*/for (i=0;i<=8;i++) line(125+i*50,5,125+i*50,285);try(1);/*调用递归函数*/delay(3000);closegraph();free(arrow);}。
八皇后问题
{
int i;
//!输出序号。
printf("No.%-5d" , ++iCount);
//!依次输出各个列上的皇后的位置,即所在的行数。
for(i = 0 ; i < QUEENS ; i++)
printf("%d " , Site[i]);
for(j=0;j<8;j++)
{
Result += N_Queens(i,j,Queens+1);
if(Result>0)
br0)
return 1;
else
{
Chessboard[LocX][LocY] = 'X';
for(i = 1 ; i <= QUEENS ; i++)
{
//!在该列的第i行上放置皇后。
Site[n] = i;
//!如果放置没有冲突,就开始下一列的试探。
if(IsValid(n))
for(i=0;i<8;i++)
for(j=0;j<8;j++)
{
if(Chessboard[i][j] == 'Q')
printf("(%d,%d)n",i,j);
}
getch();
}
/*********************************************************
if(Chessboard[i--][j++] != 'X')
回溯法实验报告
一、实验目的1. 理解回溯法的概念和基本原理。
2. 掌握回溯法的应用场景和实现方法。
3. 通过具体实例,验证回溯法在解决实际问题中的有效性。
二、实验内容本次实验主要围绕回溯法进行,通过以下实例来验证回溯法在解决实际问题中的有效性:1. 八皇后问题2. 0/1背包问题3. 数独游戏三、实验步骤1. 八皇后问题(1)定义问题:在8×8的国际象棋棋盘上,放置8个皇后,使得它们不能相互攻击。
(2)设计回溯算法:① 初始化棋盘为全空状态。
② 从第一行开始,尝试将皇后放置在每一列。
③ 如果某一列放置皇后后,不会与已放置的皇后发生冲突,则继续在下一行尝试放置。
④ 如果某一列放置皇后后,与已放置的皇后发生冲突,则回溯至上一个放置皇后的行,尝试在下一列放置。
⑤ 当所有行都放置了皇后,则找到一个解。
(3)实现代码:```pythondef is_valid(board, row, col):for i in range(row):if board[i] == col or \board[i] - i == col - row or \board[i] + i == col + row:return Falsereturn Truedef solve_n_queens(board, row):if row == len(board):return Truefor col in range(len(board)):if is_valid(board, row, col):board[row] = colif solve_n_queens(board, row + 1):return Trueboard[row] = -1return Falsedef print_board(board):for row in board:print(' '.join(['Q' if x == row else '.' for x in range(len(board))]))def n_queens():board = [-1] 8if solve_n_queens(board, 0):print_board(board)else:print("No solution exists")n_queens()```2. 0/1背包问题(1)定义问题:给定n个物品,每个物品有重量和价值,背包容量为W,求出能够装入背包的物品组合,使得背包内物品的总价值最大。
回溯法实现8皇后问题
实验题目回溯法实现8皇后问题实验要求 a.掌握递归回溯算法的基本思想。
b.学习掌握应用面向对象通用回溯程序框架解决实际问题。
提高面向对象编程的技能。
实验内容(问题描述、算法设计、算法效率)回溯法实现8皇后问题a.问题描述:在n*n格的棋盘上放置彼此不受攻击的n个皇后。
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
N后问题等价于在n*n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
b.算法设计:用n元组x[1;n]表示n后问题的解。
其中,x[i]表示皇后i放置在棋盘的第i行的第x[i]列。
由于不容许将2个皇后放在同一列上,所以解向量中的x[i]互不相同。
2个皇后不能放在同一斜线上是问题的隐约束。
对于一般的n后问题,这一隐约束条件可以化成显约束的形式。
如果将n*n 格的棋盘看做二维方阵,其行号从上到下,列号从左到右依次编号为1,2,...n。
从棋盘左上角到右下角的主对角线及其平行线(即斜率为-1的各斜线)上,2个下标值的差(行号-列号)值相等。
同理,斜率为+1的每条斜线上,2个下标值的和(行号+列号)值相等。
因此,若2个皇后放置的位置分别是(i,j)和(k,l),且i-j = k -l 或i+j = k+l,则说明这2个皇后处于同一斜线上。
以上2个方程分别等价于i-k = j-l 和i-k =l-j。
由此可知,只要|i-k|=|l-j|成立,就表明2个皇后位于同一条斜线上。
用回溯法解n后问题,用完全n叉树表示解空间。
可行性约束Place剪去不满足行,列和斜线约束的子树。
下面的解n后问题的回溯法中,递归函数Backtrack(1)实现对整个解空间的回溯搜索。
Backtrack(i)搜索解空间中第i层子树。
类Queen的数据成员记录解空间中节点信息,以减少传给Backtrack的参数。
sum记录当前已找到的可行方案数。
在算法Backtrack中,当i>n是,算法搜索至叶节点,得到一个新的n皇后互不攻击放置方案,当前已找到的可行方案数sum增1。
八皇后-回溯法
2 回溯法应用 例1 c递归回溯算法 回溯法应用-例 递归回溯算法
int a[100], n; main(){ input(n); backtrack(1); } backtrack(int k){ if (k>n) 找到一个解输出结果 找到一个解输出结果; else for (int i = 1;i <=n; i++) { a[k] = i; if (check2(a,k) = 1) backtrack(k+1); } }
13
2 回溯法应用 例1 d非递归回溯算法 回溯法应用-例 非递归回溯算法
backdate (int n) { int k; a[1]=0; k=1; while( k>0 ){ a[k]=a[k]+1; while ((a[k]<=n) and (check(a,k)=0)) //搜索第 个皇后位置 搜索第k个皇后位置 搜索第 a[k]=a[k]+1; if( a[k]<=n) ( ) if(k=n ) output(n); //找到一组解 找到一组解 else {k=k+1; //继续为第 继续为第k+1个皇后找到位置 继续为第 个皇后找到位置 a[k]=0;} //注意下一个皇后一定要从头开始搜索 注意下一个皇后一定要从头开始搜索 else k=k-1; //回溯 回溯 } }
8
queen1( ) 2 例1 a 盲目的枚举算法 check1(a[],n) { 存储x 用a[1]~a[8]存储 1~x8 存储 {int i,j; int a[9]; for(i=2;i<=n;i++) for (a[1]=1;a[1]<=8;a[1]++) for(j=1;j<=i-1;j++) for (a[2]=1;a[2]<=8;a[2]++) if (a[i]=a[j]) or for (a[3]=1;a[3]<=8;a[3]++) (abs(a[i]-a[j])=abs(i-j)) for (a[4]=1;a[4]<=8;a[4]++) return(0); for (a[5]=1;a[5]<=8;a[5]++) for (a[6]=1;a[6]<=8;a[6]++) return(1); for(a[7]=1;a[7]<=8;a[7]++) } for(a[8]=1;a[8]<=8;a[8]++){ if (check(a,8)=0) continue; else for(i=1;i<=8;i++) print(a[i]); } 9 }
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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>