回溯算法与八皇后问题N皇后问题Word版
算法——八皇后问题(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;}。
回溯法解八皇后问题

fprintf(fp," ");
}
printf("%d\n", i);
fprintf(fp, "%d\n", i);
}
printf
(".......................................................\n");
fprintf(fp,
/*/
#include <stdio.h>
#include <math.h>
#define false 0
#define true 1
#define quesize 8
int gx[quesize+1];
int sum=0;
int place( int k );
void print( int a[] );
fprintf(fp,"the sum of the ways of queens:%d\n", sum);
printf("the sum of the ways of queens:%d\n", sum);
fclose(fp);
return 1;
}
/*/////////////////////////////////////////////////////////////////////
{
int i = 1;
while ( i < k )
{ if ( ( gx[i] == gx[k] ) || ( abs( gx[i] - gx[k] )==abs( i - k ) )
数据结构与算法中的“递归”——用回溯法求解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皇后问题

算法的实现
• 假设回溯法要找出所有的答案结点 。 • 设(x1,x2,…,xi-1)是状态空间树中由根到一个结 点的路径,而T(x1,…xi-1)是下述所有结点xi的 集合,它使得对于每一个xi,(x1,x2,…,xi)是由 根到一个结点xi的路径;假定还存在着一些限 界函数Bi,如果路径(x1,x2,…,xi)不可能延伸到 一个答案结点,则Bi(x1,x2,…,xi)取假值,否则 取真值。 • 于是解向量X(1:n)中的第i个分量,就是那些 选自集合T (x1,x2,…,xi-1)且使Bi为真的xi
HHIT
算法8.5:n-皇后问题的解
Algorithm
Procedure NQUEENS(n) //此过程使用回溯法求出一个n*n棋盘上放置n个皇后,使其不能互相攻 击的所有可能位置// integer k,n,X(1:n) X(1)0 ; k1 // 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 //不能放则转到下一列// repeat if X(k)<=n then //找到一个位置// if k=n then print (X) //是一个完整的解则打印这个数组// else kk+1;X(k)0 //否则转到下一行// end if else kk-1 //回溯// end if repeat End NQUEENS
HHIT
Algorithm
显然,棋盘的每一行上可以而且必须摆放一个皇后, 所以,n皇后问题的可能解用一个n元向量X=(x1, x2, …, xn) 表示,其中,1≤i≤n并且1≤xi≤n,即第i个皇后放在第i行第 xi列上。 由于两个皇后不能位于同一列上,所以,解向量X必 须满足约束条件: xi≠xj (式8.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++)
八皇后以及N皇后问题分析

⼋皇后以及N皇后问题分析⼋皇后是⼀个经典问题,在8*8的棋盘上放置8个皇后,每⼀⾏不能互相攻击。
因此拓展出 N皇后问题。
下⾯慢慢了解解决这些问题的⽅法:回溯法:回溯算法也叫试探法,它是⼀种系统地搜索问题的解的⽅法。
回溯算法的基本思想是:从⼀条路往前⾛,能进则进,不能进则退回来,换⼀条路再试。
在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满⾜某种要求的可能或最优的情况,从⽽得到整个问题的解。
回溯算法就是解决这种问题的“通⽤算法”,有“万能算法”之称。
N皇后问题在N增⼤时就是这样⼀个解空间很⼤的问题,所以⽐较适合⽤这种⽅法求解。
这也是N皇后问题的传统解法,很经典。
算法描述:1. 算法开始,清空棋盘。
当前⾏设为第⼀⾏,当前列设为第⼀列。
2. 在当前⾏,当前列的判断放置皇后是否安全,若不安全,则跳到第四步。
3. 在当前位置上满⾜条件的情况: 在当前位置放⼀个皇后,若当前⾏是最后⼀⾏,记录⼀个解; 若当前⾏不是最后⼀⾏,当前⾏设为下⼀⾏,当前列设为当前⾏的第⼀个待测位置; 若当前⾏是最后⼀⾏,当前列不是最后⼀列,当前列设为下⼀列; 若当前⾏是最后⼀⾏,当前列是最后⼀列,回溯,即清空当前⾏以及以下各⾏的棋盘,然后当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置; 以上返回第⼆步。
4.在当前位置上不满⾜条件: 若当前列不是最后⼀列,当前列设为下⼀列,返回到第⼆步; 若当前列是最后⼀列,回溯,即,若当前⾏已经是第⼀⾏了,算法退出,否则,清空当前⾏以及以下各⾏的棋盘,然后,当前⾏设为上⼀⾏,当前列设为当前⾏的下⼀个待测位置,返回第⼆步。
如何判断是否安全:把棋盘存储为⼀个N维数组a[N],数组中第i个元素的值代表第i⾏的皇后位置,这样便可以把问题的空间规模压缩为⼀维O(N),在判断是否冲突时也很简单, ⾸先每⾏只有⼀个皇后,且在数组中只占据⼀个元素的位置,⾏冲突就不存在了, 其次是列冲突,判断⼀下是否有a[i]与当前要放置皇后的列j相等即可。
数据结构课程设计 回溯法解决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。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
回溯算法与八皇后问题(N皇后问题)1 问题描述八皇后问题是数据结构与算法这一门课中经典的一个问题。
下面再来看一下这个问题的描述。
八皇后问题说的是在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。
更通用的描述就是有没有可能在一张N*N的棋盘上安全地放N个皇后?2 回溯算法回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。
回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满足某种要求的可能或最优的情况,从而得到整个问题的解。
回溯算法就是解决这种问题的“通用算法”,有“万能算法”之称。
N皇后问题在N增大时就是这样一个解空间很大的问题,所以比较适合用这种方法求解。
这也是N皇后问题的传统解法,很经典。
下面是算法的高级伪码描述,这里用一个N*N的矩阵来存储棋盘:1) 算法开始, 清空棋盘,当前行设为第一行,当前列设为第一列2) 在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步3) 在当前位置上满足条件的情形:在当前位置放一个皇后,若当前行是最后一行,记录一个解;若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;若当前行是最后一行,当前列不是最后一列,当前列设为下一列;若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;以上返回到第2步4) 在当前位置上不满足条件的情形:若当前列不是最后一列,当前列设为下一列,返回到第2步;若当前列是最后一列了,回溯,即,若当前行已经是第一行了,算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置,返回到第2步;算法的基本原理是上面这个样子,但不同的是用的数据结构不同,检查某个位置是否满足条件的方法也不同。
为了提高效率,有各种优化策略,如多线程,多分配内存表示棋盘等。
为了便于将上述算法编程实现,将它用另一种形式重写:Queen()Loop:if check_pos(curr_row, curr_col) == 1 thenput_a_queen(curr_row, curr_col);if curr_row == N thenrecord_a_solution();end if;if curr_row != N thencurr_row = curr_row + 1;curr_col = 1;elseif curr_col != N thencurr_col = curr_col + 1;elsebacktrack();end if;end if;elseif curr_col != N thencurr_col = curr_col +1;elsebacktrack();end if;end if;end Queen;3 实现3.1 数据结构这里,用一个N个元素的一维数组来表示。
数组的下标表示棋盘的行,数组的元素表示该行皇后所在的列。
这个结构自然就消除了列冲突,因为每一行只有一个皇后。
还有利用它解决行冲突,也很简单,只要比较各个元素就行了,看有没有相等的元素。
斜线冲突也简单,因为同一斜线上的在一直线上,该直线的斜率为+1(左下至右上)或-1(左上至右下),所以,左下至右上的冲突检测方法为看式子是否成立(row –curr_row)/(col –curr_col) = 1,也就是(row - col) = (curr_row –curr_col),相同,则有冲突。
同理,左上至右下看式子(row + col) = (curr_row +curr_col)。
这里,也是看下标与其对应元素的和与差是不是与要检测位置的相应结果相同,如果有一个相同,就有冲突。
数据结构一确定,冲突检测方法就有了,关键的部分的算法就完成了。
3.2 代码/*************************************************************** File: NQueen.cDescripton: N皇后问题求解之回溯版Author: liuqh, Hunan UniversityDate: 2007.5.22, Tues.Version: 1.0**************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <math.h>#define SOLS(n) (int)(pow(2.0, (double)(n)))#define DEBUG/*************************全局变量定义**************************/int N = -1; /*棋盘的大小*/char *p_board = NULL; /*指向棋盘,这里是用一个长度为N 的一维数组表示的*/char *buf = NULL; /* 输出缓冲 */int buf_index = -1;/*********************************本编译单元的函数声明*********************************/static int queen(FILE *fp);static int clear_board(int i);static int check_pos(int curr_row);static int record_a_solution(FILE *fp, int solutions);static int backtrack(int *p_curr_row);static void flush_buf(FILE *fp, int solutions);/*** 函数:main()** 功能:程序入口** 入口: 参数个数(整型);程序名与N的大小** 出口:** 返回:成功返回0,否则返回-1** 备注:*/int main(int argc, char **argv){clock_t start, finish;double duration;int solutions;FILE *fp;/* 命令行参数检查*/if (argc != 2){fprintf(stderr, "用法: queen N\n") ;return -1;}N = atoi(argv[1]);if (N <= 0){fprintf(stderr, "用法: queen N \n N必须大于0\n") ;return -1;}/*开始计时*/start = clock();p_board = (char*)calloc(N, sizeof(char));if (NULL == p_board){fprintf(stderr, "为棋盘分配内存失败\n") ;return -1;}fp = NULL;if ((fp = fopen("solutions.txt", "w")) == NULL){free(p_board);fprintf(stderr, "创建文件solutions.txt失败!\n") ;return -1;}solutions = queen(fp);if (-1 == solutions){free(p_board);if (fclose(fp) == EOF){fprintf(stderr, "关闭文件solutions.txt失败!\n") ;return -1;}fprintf(stderr, "调用queen()失败\n") ;return -1;}printf("共有%d种解决方案,具体结果请查看文件solutions.txt\n", solutions) ;fprintf(fp, "solutions = %d\n", solutions);free(p_board);/*操作完成,计时结束*/finish = clock();/*计算时间间隔,以秒为单位*/duration = (double)(finish - start) / CLOCKS_PER_SEC;printf("计算完毕,共耗时%f秒!\n", duration);fprintf(fp, "time = %f\n", duration);if (fclose(fp) == EOF){fprintf(stderr, "关闭文件solutions.txt失败!\n") ;return -1;}return 0;}/*** 函数:queen()** 功能:计算N皇后问题的解** 入口: 记录结果的文件指针** 出口:** 返回:成功返回解的个数,出错返回-1** 备注:*/int queen(FILE *fp){int curr_row;int result;result = 0;if (clear_board(0) == -1){fprintf(stderr, "清空棋盘失败!\n") ;return -1;}curr_row = 0;p_board[curr_row] = (char)0;buf = (char*)calloc(SOLS(N)*N, sizeof(char));if (NULL == buf){fprintf(stderr, "为解分配内存失败\n") ;return -1;}while (1){if (check_pos(curr_row)== 1){if (N-1 == curr_row){result++;record_a_solution(fp, result);}if (curr_row != N-1){curr_row++;p_board[curr_row] = (char)0;continue;}}if (p_board[curr_row] != (char)(N-1)){p_board[curr_row] ++;}else{if (backtrack(&curr_row) == 1){break;}}} /* end while */flush_buf(fp, result);free(buf);return result;}/*** 函数:clear_board()** 功能:初始化棋盘** 入口: 初始化开始的行(整型), 全局变量p_board, N ** 出口:初始化后的棋盘,这里指指针p_board指向的数组** 返回:成功返回0,出错返回-1** 备注:*/int clear_board(int i){if (memset(&p_board[i], -1, N-i) == NULL){return -1;}return 0;}** 函数:check_pos()** 功能:检查某个位置是否能放一个皇后** 入口: 位置所在的行(整型), 全局变量p_board, N** 出口:** 返回:可以放置的话返回1,否则返回0** 备注:*/int check_pos(int curr_row){int i;int sum, sub;/*检查是否有行冲突*/for (i = 0; i < curr_row; i++){if (p_board[i] == p_board[curr_row]){return 0;}}/*检查斜线方向的冲突*/sum = curr_row + p_board[curr_row];sub = curr_row - p_board[curr_row];for (i = 0; i < curr_row; i++){if (i+p_board[i] == sum || i - p_board[i] == sub){return 0;}}return 1;}** 函数:record_a_solution()** 功能:记录一个合法的解** 入口:记录结果的文件指针;解的个数(整型)全局变量p_board, N** 出口:存储解的缓存buf(字符串)** 返回:成功,返回0,否则返回-1** 备注:解先缓存在内存中,这样快一点,要提高速度,修改SOLS宏以获得更大的缓冲区*/int record_a_solution(FILE *fp, int solutions){if (++buf_index != SOLS(N)){if (memcpy(&buf[buf_index*N], p_board, N) == NULL){fprintf(stderr, "拷贝解到缓冲时出错!\n") ;buf_index--;return -1;}}else{flush_buf(fp, solutions);}return 0;}/*** 函数:backtrack()** 功能:回溯到上一行** 入口: 全局变量p_board, N** 出口:当前行(整型指针)** 返回:可以回溯,返回0,否则返回1,表示算法可以退出了** 备注:可能递归调用自身*/int backtrack(int *p_curr_row){if (0 == *p_curr_row){if (clear_board(p_board[*p_curr_row]) == -1){fprintf(stderr, "backtrack():清空棋盘失败!\n") ;}return 1; }if (clear_board(p_board[*p_curr_row]) == -1){fprintf(stderr, "backtrack():清空棋盘失败!\n") ;return -1;}(*p_curr_row)--;if (p_board[*p_curr_row] != N-1){p_board[*p_curr_row]++;return 0;}else{return backtrack(p_curr_row);}}/*** 函数:flush_buf()** 功能:刷新缓冲区** 入口: 记录结果的文件指针;当前全部解的个数(整型);全局变量buf,buf_index, N** 出口:** 返回:** 备注:*/void flush_buf(FILE *fp, int solutions){int k,i, j;for (k = 0; k <= buf_index; k++){fprintf(fp, "solutions %d\n",solutions - (buf_index - k));fprintf(fp, "--------------------------------------\ n");for (i = 0; i < N; i++){for (j = 0; j < N; j++){fprintf(fp, "%3c", j == buf[k*N+i] ? 'Q' : 'x');}fprintf(fp, "\n");}fprintf(fp, "--------------------------------------\ n");}buf_index = -1;}(注:可编辑下载,若有不当之处,请指正,谢谢!)。