n皇后问题的解决 (QS2算法)
来源:互联网 发布:前置过滤器 知乎 编辑:程序博客网 时间:2024/05/16 07:31
n皇后问题的解决 (QS2算法)
8皇后问题是一个广为人知的问题:将8个皇后放在8×8的棋盘上,皇后之间不能互相攻击,求各种放法。更一般的,把8换成n,其解法个数是随n成几何级增长的,因此程序运行时间也是几何级别的。现在我们关注这样一个问题,既然不能很快的把所有解都枚举出来,那么我们能不能很快的求出一个解来呢?这就是n皇后问题。
有人说,我就用纯搜索来搜第一个解,会不会快呢?你可以试一试,当n增大的时候会变的非常非常慢。除了搜索,还能有什么更好的办法呢?下面介绍一个QS2算法,可以在当n大到500000的时候仍能在几分钟之内得到解。
描述算法前,先定义一些数据结构:
1. 状态表示。用queen[i] (1<=i<=n)存储1..n个一个排列,用它表示第i列的皇后所放的行数。这样表示的作用是,同一行同一列都不会有互相攻击的情况发生,发生攻击的只可能是对角线。
2. 对角线标记。对于第i行第j列的元素,它有两个方向的对角线。假设以左下角为坐标(1,1)点,那么一条对角线是斜率为正的,另外一条是斜率为负的。对于斜率为正的对角线上的元素,i-j为定值,对斜率为负的对角线上的元素,i+j为定值,因此用i+j来标记该元素所处的负对角线,用i-j来标记其所处的正对角线。用数组dn[ ]来表示第i+j条负对角线上有多少个皇后,用dp[ ]来表示第i-j条正对角线上的皇后的个数。定义在某条对角线上,碰撞的个数为这条对角线上皇后的个数减1。
3. 被攻击的皇后。用一个数组attack[ ]来存储所有被攻击的皇后的行数。此数组用于加速程序的运行。
有了这些数据结构,就可以开始介绍QS2算法了。
算法如下:
1. repeat
2. 随机产生初始状态queen[i]
3. collisions = compute_collisions(queen, dn, dp) (计算每个对角线上皇后的个数,dp[]和dn[],并计算总的碰撞次数collisions)
4. 设limit = C1 * collisions (该变量用于界定程序中每种状态产生的碰撞次数,C1是一个参数,这里设为0.45)
5. number_of_attacks = compute_attacks(queen, dn, dp, attack) (计算被攻击的皇后的个数)
6. loopcount = 0
7. repeat
8. for k <- 1 to number_of_attacks do
9. i <- attack[k]
10. 随机选择一个1..n之间的数j
11. if 交换queen[i]和queen[j]可以减少总的碰撞次数collisions then
12. 进行这次交换,并重新计算dn[], dp[]和collisions
13. if collisions = 0 then 找到解,结束。
14. if collisions < limit then do
15. limit <- C1*collisions
16. 重新计算number_of_attacks = compute_attacks(queen, dn, dp, attack)
17. end do
18. end do
19. end do
20. loopcount <- loopcount + number_of_attacks
21. until loopcount > C2 * n (C2是一个常量,这里设为32)
22. until collisions = 0
通观这个算法,发现其实很简单,就是先随机产生了一种排列方案,然后找一个被攻击的皇后,随机选择另一个皇后,让她们交换位置,如果这个交换可以使总的碰撞次数减少,那么就进行交换。由于这个算法是随机的,不能保证从最开始随机产生的queen[i]状态一定可以得到一组解,因此,程序在运行一段时间之后,如果没有解产生,就重新产生一组初始值(这个过程是通过loopcount变量来控制的)。
再看看这个算法的性能。由于程序里面充满了随机化,对这个程序的性能的分析也无法直接从代码中来分析其复杂度。它的性能是通过实验来分析的。下面这个表列出了一些统计数字:
皇后个数n 1000 10000 100000 500000
被测试的皇后对个数 14742 138762 1386974 6981193
进行交换的皇后对个数 436 4333 43256 216407
表中第2行被测试的皇后对个数,是指程序第11行对两个皇后交换后是否可以减少碰撞个数的测试。表中第3行进行交换的皇后对个数,是指程序第12行交换两个皇后的次数。
从表中我们不难发现,随着n增大,测试皇后对和交换皇后对这两个操作都是呈线性增加的。也就是说,对由一个初始状态出发到产生解,所用时间是线性的。但是,如果不能从某个随机的初始状态产生出解呢?虽说若不能出解,程序运行一段时间后会重新产生初始状态,但如果不能产生解的初始状态很多,那么程序的性能也会大大下降。事实上这个顾虑是多余的,实验验证,当n超过1000的时候,几乎总可以从第一个初始值出发找到解!
这个算法介绍完了,最后,我想说说我对这个算法的感觉。首先,这个算法是实验性的。其性能的评估没法用传统的复杂度分析方法来进行,必须通过实验来验证。当我看到了这个算法,如果不是亲自去写一遍,我根本无法相信它会这么快的出解,这也是它神奇的地方。其次,这个算法的思路跳出了解决n皇后问题一般所能想到的回溯搜索方法,取而代之的是一个随机化贪心算法。虽然说它是不确定的,可是它却快速的解决了问题。这为人们提供了一个思路,当遇到传统的搜索很难奏效的时候,随机化贪心也许会另辟捷径,收到意想不到的效果。
- n皇后问题的解决 (QS2算法)
- QS2算法求解N-皇后问题
- N皇后问题的解决
- php回溯算法解决n皇后问题
- N皇后问题(算法)
- N皇后问题算法
- N皇后问题算法
- 【算法】n皇后问题
- 算法-n皇后问题
- 算法 N皇后问题
- 【算法分析】回溯法解八皇后问题(n皇后问题)
- 目前最快的N皇后问题算法!!!
- 目前最快的N皇后问题算法!!!
- N皇后问题的非递归算法
- [算法]经典算法8皇后(N皇后)问题的解法,C语言实现
- 回溯法解决2n皇后(8皇后)问题
- N皇后问题(回溯算法解法)
- lv 算法与回溯法相结合解决n皇后问题
- 关于(WTL),怎么在OnCreate中调用DwmExtendFrameIntoClientArea()这个API(vista系统的毛玻璃效果)
- 2.6.16核心的linux支持的电视卡的card类型和tuner类型
- ubuntu 6.10 edgy下安装jdk1.6和永中office2007
- asp.net创建文件夹的IO类的问题
- 服务端客户端常用方法(asp.net javascript)
- n皇后问题的解决 (QS2算法)
- xmlhttp的状态码收集
- 使用dscaler在windows下播放电视的设置
- 用一根网线连接两台电脑构成小型局域网
- C#学习笔记(二)
- C#学习笔记(三)
- 基础学习 C#之一
- 装php+mysql+apache+MT怎么这么麻烦啊?
- C#学习笔记(四)