(1) 本算法使用递归回溯实现。算法使用二进制的一位了表示此列是否放置了皇后, 1 表示已被皇后占领, 0 表示没有被占领。算法遍历第一行的所有列,先从第一行最后一列开始探索,找到符合的点以后(不跟前面已经放置了皇后的同一行、列,也不是对角线关系),然后递归探索下一行的剩下没被占领的列,如果最后所有的列都放满了皇后,则探索成功,打印出探索结果(按行递增的方向打印列号),然后返前面一行,探索剩下没被占领的列……如果找出了所有从最后一列开始探索的所有结果,则递归返回,继续从 n-1 列开始的递归探索,直到第 1 行的所有列都探索完了,算法结束。本算法列编号从第 n 列开始往回递增,即第 n 列编号为 1 ,第 n-1 列编号为 2 ……第一列编号为 1.
(2) 算法为了提供更多的信息,加入了记录探索成功的次数和使用时间。
(3) 程序中为变量 column ,初始化为低 n 位为 1 ,表示所有列,用于标识探索是否完成, row 为已被皇后占领了的列,相应的位(对应相应的列)被置为 1 ,初始值为 0 。
(4) 程序开始时使用默认的皇后,如果用户从控制台输入皇后的参数,则使用输入参数。然后利用 n 的值来设定列的标识 column ,用于判定递归探索过程中是否结束。接着记录当前时间,进入递归探索。
(5) 递归探索接受一个记录已被占领列的参数 row ,右对角线 rightdiagonal ,左对角线 leftdiagnal ,记录探索的列的序号 result 。函数首先判断已被占领的列 row 是否和所有的列相等,如果相等,说明每一列都被占领了,此方案可行,打印出该方案( cout<<result.c_str()<<endl; ),然后记录可行数 sum++ ,否则继续探索下一行剩下的列 pose , p 为本次探索的列最右边的一列,此时剩下的列应减去这一列( pos = pos-p )在探索每一列时,递归探索下一行的剩下所有剩下列,作为递归的参数已被占领的列应该增加一列(当前的列标记为占领, row+p ),当前点的右对角线列不可用( (rightdiagonal+p)<<1 ),左对角线也不可用( (leftdiagonal+p)>>1 ),已探索的列的序号增加当前列( _itoa(log((double )p)/log(2.0)+1,tmp,10); result + tmp + " " ),进入下一次递归。当所有递归返回时,探索完成,探索过程中已经输出所有探索成功的列的序号。然后输出探索成功的次数,和现在时间减去算法开始时记录的时间所得的算法所用的时间。
(6) 算法使用了二进制中的一位而不是常规的的数组来表示一列,提高了算法的效率。算法没有直接体现了遍历 N*N 个格,而是遍历第一行的所有列,在遍历每一列时,递归遍历下一行的所有没被占领的列,如此类推,当返回时对下一列做同样的遍历,当所有列遍历完了以后,便得出了所有的结果,即对每一个个都遍历了。
算法的两个亮点:使用一位来表示一列,通过传递 已被遍历列的序列号 在每次递归中记录列的遍历序列,最后尝试成功后打印出来。
运行效果:
本文介绍了一种使用递归回溯算法解决N皇后问题的方法,该算法能够在N×N的棋盘上放置N个皇后,并确保任意两个皇后不会在同一行、列或对角线上。通过高效的二进制位操作来标记已放置皇后的位置,减少了不必要的计算。

877

被折叠的 条评论
为什么被折叠?



