回溯法及其应用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
八皇后问题的基本策略及其应用
郭洋洋王刚李晴孙佳
(陕西师范大学计算机科学学院09级计算机科学与技术,西安,710062)
摘要:针对八皇后问题,本文采用回溯法,给出递归与非递归两种算法的设计与分析,并通过实验验证两种算法的性能,得出最佳的算法。
关键词:八皇后;回溯法;递归算法;非递归算法
The Basic Algorithm Strategy For Eight Queens
And Its Application
Guo Yangyang,Wang Gang,Li Qing, Sun Jia
(School of Computer Science ,Shanxi Normal University ,Xi’an ,710062 )
Abstract: Aiming at the problem of Eight Queens,this paper gives Backtracking , and Recursive algorithm and Non-recursive algorithm , and show the design and analysis of the two kinds of algorithms,and through the experiment ,verified the performance of them,getting the most suitable algorithm.
Keywords: Eight Queens; Backtracking; Recursive; Non-Recursive
1 引言
八皇后问题由19 世纪著名的数学家高斯在1850 年提出:在8 ×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法.
回溯算法是尝试搜索算法中最为基本的一种算法,其采用了一种“走不通就调头”的思想,作为其控制结构[1]。回溯法在用来求问题的所有解时,要回溯到根,且根节点的所有可行的子树都已被搜索遍才结束。而回溯法在用来求解问题任一解时,只要搜索到问题的一个解就可以结束。这就是以深度优先的方式系统的搜索问题解的回溯法,它适用于解决一些类似n皇后问题等就切方案问题,也可以解决一些最优化问题。
2 问题描述与模型
八皇后问题:在8 ×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法.
例如图一所示:
图一 8皇后问题
模型建立:不妨设8个皇后为x i ,她们分别在第i行(i=1,2,3,…,8),这样问题的解空间,就是一个8皇后所在列的序号,为n元一维向量(x1,x2,x3,x4,x5,x6,x7,x8),搜索空间是1≤x i≤8(i=1,2,3,…,8),共88个状态。约束条件是8个点(1,x1),(2,x2),(3,x3),(4,x4),(5,x5),(6,x6),(7,x7),(8,x8),不在同一列和同一对角线上。
3 算法设计
下面通过枚举法、非递归算法、递归算法来求解问题。
3.1 枚举法
算法设计:
运用枚举法解决此问题是通过八重循环,按照深度优先思想,从第一个皇后开始搜索,确定第一个位置后,在搜索第二个位置;……;每进一步检查是否满足约束条件,不满足时,用continue回溯到上一个皇后继续寻找;满足约束条件时,开始下一个皇后的搜索;直到找出问题的解。
显然,问题的搜索空间有88个状态。约束条件有有三个[1]:
(Ⅰ)不在同一列的表达式为:x i≠x j
(Ⅱ)不在同一主对角线上的表达式为:x i-i≠x j-j;
(Ⅲ)不在同一负对角线上的表达式为:x i+i≠x j+j;
以上条件和可以合并为一个“不在同一对角线上”的约束条件,表达式为:
abs(x i-x j)≠abs(i-j)(abs()取绝对值)。
算法伪代码如下:
main()
{
for ( a[1]=1; a[1]<=8;a[1]=a[1]+1)
for(a[2]=1;a[2]<=8;a[2]=a[2]+1)
{if (check(a,2)= =0) continue;
for (a[3]=1;a[3]<=8;a[3]=a[3]+1)
{if (check(a,3)= =0) continue;
for (a[4]=1;a[4]<=8;a[4]=a[4]+1)
{ if (check(a,4)= =0) continue;
for (a[5]=1;a[5]<=8;a[5]=a[5]+1)
{if (check(a,5)= =0) continue;
for (a[6]=1;a[6]<=8;a[6]=a[6]+1)
{if (check(a,6)= =0) continue;
for (a[7]=1;a[7]<=8;a[7]=a[7]+1)
{if (check(a,7)= =0) continue;
for (a[8]=1;a[8]<=8;a[8]=a[8]+1)
{if (check(a,8)= =0) continue;
else
for (int i=1;i<=8;i++)
printf (a[i]);
}}}}}}}}
check( a,i) 功能:
将第i个皇后和前i-1个皇后比较,如果满足上述三个约束条件,则继续寻找第i+1个皇后的位置;否则,继续查找第i个皇后;若找不到则返回0;否则返回1.
算法分析1:
表面上看,这个算法的时间复杂度为88,其实算法在check()函数返回0时,continue 返回,便不再执行其后的皇后查找工作,所以其时间复杂度并没有88。
当然,我们可以将算法稍微改变后,它的复杂度便立即为88。在算法中:
将前七个“if (check(a[],i)==0) continue;”去掉,只留下最后一个,同时将check 函数改为如下:
_check(a[],n)
{
int i,j;
for (i=2;i<=n;i++)
for (j=1;j if((abs(a[i]-a[j])==abs(i-j))||(a[i]=a[j])) return 0; return 1; } 此时算法退化为完全的盲目搜索,算法的复杂性就是88。 3.2 非递归算法 虽然枚举法有很好的可读性,从continue也可以看出回溯算法的思想,可是她只能解决常量个皇后的问题,不能解决任意个n个皇后的问题,因此也不是典型的回溯法模型。 下面的非递归算法是典型的回溯算法模型。 非递归算法框架: int a[n]; int i; 初始化数组a[]; i=1; while(i>0(有路可走)and([未达到目标])) { if(i>n)