因为这学期的算法分析课快要完了,也差不多进入复习阶段了,所以在这就把学习到的一些比较经典的算法拿出来晒晒,可能不是最好的,但怎么说也是为解决问题提供了一个思路。关于算法,有很多类型的问题,我在这里就拣一个复习一个了,呵呵。
今天要写的算法是源于八皇后问题,但在这里为了说明普遍性,直接介绍N皇后问题,与八皇后问题思路一样。这是ACM中一道典型的回溯题,当然其它方法也能对其求解,但毫无疑问回溯得到的解是最准确无误的。
一、问题描述:
在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上。
输入:
给定棋盘的大小n (n ≤ 13)
输出:
输出有多少种放置方法。
二、解题思路:
要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行、同一列、同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇后放置在第i行的哪一列,所以在放置第i个皇后的时候,可以从第1列判断起,如果可以放置在第1个位置,则跳到下一行放置下一个皇后。如果不能,则跳到下一列...直到最后一列,如果最后一列也不能放置,则说明此时放置方法出错,则回到上一个皇后向之前放置的下一列重新放置。此即是回溯法的精髓所在。当第n个皇后放置成功后,即得到一个可行解,此时再回到上一个皇后重新放置寻找下一个可行解...如此后,即可找出一个n皇后问题的所有可行解。
三、复杂度分析:
关于N皇后问题的复杂度问题可以说是众说纷纭了,自己也改变过好几次,刚开始以为棋盘是n行n列,所以理所当然应该是n^2,后来发现在每列选择可否放置的比较上又做了一次循环,所以应该是n^3,但想了很久,发现判断可否放置的时候不是每次都循环到n,它是根据皇后i的取值而变化的,所以复杂度应该是1/3 n^3左右,即是小于n^3的。
四、测试代码:
在这里我写了两个实现方法,一个是递归回溯,一个是迭代回溯,思路都一样,只是形式不同罢了。
递归回溯:
#include<stdio.h>
#define N 15
int n; //皇后个数
int sum = 0; //可行解个数
int x[N]; //皇后放置的列数
/*
*判断函数,判断第k个皇后是否可以放在某一个位置
*如果与之前的皇后出现在同一列或同一对角线则放置失败,返回0,否则返回1
*/
int place(int k)
{
int i;
for(i=1;i<k;i++)
if(abs(k-i)==abs(x[k]-x[i]) || x[k] == x[i])
return 0;
return 1;
}
/*
*求解可行解函数,当第t个皇后可以放置在t行的某一位置时,继续放置下一皇后,直到
*所有皇后放置结束,如果某一皇后不能放置,则移向下一列放置,如果这一列都不能放
*置或所有皇后放置结束,返回上一皇后重新放置,最终返回所有可行解个数。
*/
int queen(int t)
{
if(t>n && n>0) //当放置的皇后超过n时,可行解个数加1,此时n必须大于0
sum++;
else
for(int i=1;i<=n;i++)
{
x[t] = i; //标明第t个皇后放在第i列
if(place(t)) //如果可以放在某一位置,则继续放下一皇后
queen(t+1);
}
return sum;
}
int main()
{
int t;
scanf("%d",&n);
t = queen(1);
if(n == 0) //如果n=0,则可行解个数为0,这种情况一定不要忽略
t = 0;
printf("%d",t);
return 0;
}
迭代回溯:
#include<stdio.h>
#define N 15
int n;
int sum = 0;
int x[N];
int place(int k)
{
int i;
for(i=1;i<k;i++)
if(abs(k-i)==abs(x[k]-x[i]) || x[k] == x[i])
return 0;
return 1;
}
int queen()
{
x[1] = 0;
int t=1;
while(t>0)
{
x[t]+=1;
while(x[t]<=n && !place(t))
x[t]++;
if(x[t]<=n)
if(t == n)
sum++;
else
x[++t] = 0;
else
t--;
}
return sum;
}
int main()
{
int t;
scanf("%d",&n);
t = queen();
printf("%d",t);
return 0;
}
迭代回溯的注释因为和递归回溯差不多,所以就不再附注了。在这里我们可以看到,递归回溯非常简单,结构很清晰,但它有一个潜在的问题存在,即当随着变量n的增大,递归法的复杂度也将成几何级增长,也有可能会出现重复的情况,所以我们在解决问题时,如果能用迭代法解决,最好还是不要用递归法,除非你已经对这个递归了如指掌了。
通过这个N皇后问题,我想大概已经把回溯法讲得很清楚了吧,回溯法得到的解展开就是一个树,很多方法都是可以通过回溯法来解决的,效率很高,但如果基数过大的话,回溯法就显得不是那么适用了,这也是回溯法的弱势吧。比如说这个N皇后问题,好像当n>60的时候,回溯法就不能完全地解决问题了,这时可以考虑用概率算法来解决,它可以解决很大的基数,只不过结果不是很精确而已。所以我们在面对一个问题时,具体是使用什么算法还是要结合实际情况来考虑的,目的都是更方便、更准确地解决问题。
分享到:
相关推荐
回溯法是一种重要的算法设计与分析技术,...通过对n皇后问题的求解,我们可以学习到如何设计和实现回溯算法,以及如何用编程语言(如C++)来表达这些算法思想。同时,这也有助于提升我们的逻辑思维能力和问题解决能力。
《算法分析与设计实验五 N皇后》实验报告主要围绕N皇后问题展开,旨在让学生掌握回溯递归算法和迭代算法的设计与实现,并通过N皇后问题的实际解决,理解回溯法的核心思想。N皇后问题是一个经典的计算机科学问题,...
在描述N皇后问题的算法时,我们首先需要理解棋盘的结构和皇后的攻击规则。每个皇后占据棋盘上的一个格子,可以沿着行、列和两条对角线攻击其他格子。因此,我们需要确保没有两个皇后位于同一行、同一列或同一对角线...
这是一段描述怎样解决N皇后问题的源代码,希望会对你有所帮助,仅代表个人想法,有错请指正
N皇后问题 C++ 递归 回溯 算法分析与设计
### 应用搜索原理解N皇后问题算法分析及优化 #### 摘要 N皇后问题是一个经典的组合问题,涉及到将N个皇后放置在一个N×N的棋盘上,使得任意两个皇后都不会互相攻击(即不在同一行、同一列或同一斜线上)。本文通过...
n 皇后问题是一道经典的回溯算法问题,其目标是在一个 � × � n×n 的棋盘上放置 � n 个皇后,使得任意两个皇后都不能在同一行、同一列或同一斜线上。 栈可以用来辅助实现回溯算法,本质上就是手动维护了递归...
n皇后问题是一类著名的图算法问题,要求在棋盘上放置n个皇后,使得它们互不攻击。所谓互不攻击,指的是任意两个皇后都不在同一行、同一列及同一对角线上。本问题通过特定的算法来寻求问题的所有解。 在本例中,以n=...
N皇后问题,完全原创,感觉挺不错的,哈哈
使用递归方法解决了n皇后问题,初学递归的朋友可以参考一下!
### N皇后问题递归算法详解 ...通过以上分析,我们可以看到N皇后问题不仅是一个简单的数学问题,而且还是一个很好的递归与回溯算法的教学案例。理解其背后的逻辑和原理对于学习计算机科学的相关知识非常有帮助。
### N皇后问题Las Vegas优化算法的实现 #### 引言 N皇后问题是一个经典的计算机科学问题,涉及到在N×N的棋盘上放置N个皇后,使得任何两个皇后都不在同一行、同一列或同一对角线上。这个问题不仅具有数学上的趣味...
算法分析的实验,n皇后,c语言,以矩阵形式列出
### N皇后问题实验报告知识点解析 ...通过本实验,学生不仅能够深入了解N皇后问题的算法原理,还能够掌握如何利用递归和回溯技术来解决问题。此外,通过实际编程操作,还能进一步提高学生的逻辑思维能力和编程技巧。
该算法解决了 N 皇后问题,即在 N×N 格的国际象棋上摆放 N 个皇后,使其不能互相攻击的摆法问题。该算法的优化设计是通过对 C 语言的知识进行分析和改进,提高程序的运行效率。 关键词:C 语言、回溯、递归 1. ...
根据给定的信息,我们可以整理出有关“N皇后问题”的详细知识点。 ### N皇后问题概述 ...综上所述,N皇后问题是计算机科学中一个非常经典的算法问题,其涉及到的数据结构、算法设计及优化策略都非常值得深入研究。
n皇后问题代码 回溯法 递归回溯 算法设计与分析
与八皇后类似,只是可以输入任意N值。
N皇后问题是一个经典的计算机科学问题,它涉及到在N×N的棋盘上放置N个皇后,使得皇后之间不能互相攻击,即任何两个皇后都不能处于同一行、同一列或同一对角线上。这个问题常用于演示回溯算法和递归在解决约束满足...