N皇后问题 回溯法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
N皇后问题
在一个n*n的国际象棋棋盘上放置n个皇后,使得它们中任意2个之间都 不互相“攻击”,即任意2个皇后不可在同行、同列、同斜线上。 输出N,⑴求N皇后问题的一种放法;
⑵求N皇后问题的所有放法
分析: N=4时,右图是一组解
要素一: 解空间
一般想法:利用二维数组,用[i,j]确定一个皇后位置!
优化:利用约束条件,只需一维数组即可! x:array[1..n] of integer; x[i]:i表示第i行皇后 x[i]表示第i行上皇后放第几列
注意:同一个问题可以有多种表示,有些表示方法更简单, 所需表示的状态空间更小(存储量少,搜索方法简单)。
n=3时的0-1背包问题用完全二叉树表示的解空间
生成问题状态的基本方法
► ► ► ►
► ►
扩展结点:一个正在产生儿子的结点称为扩展结点 活结点:一个自身已生成但其儿子还没有全部生成的节点称 做活结点 死结点:一个所有儿子已经产生的结点称做死结点 深度优先的问题状态生成法:如果对一个扩展结点R,一旦 产生了它的一个儿子C,就把C当做新的扩展结点。在完成 对子树C(以C为根的子树)的穷尽搜索之后,将R重新变成 扩展结点,继续生成R的下一个儿子(如果存在) 宽度优先的问题状态生成法:在一个扩展结点变成死结点 之前,它一直是扩展结点 回溯法:为了避免生成那些不可能产生最佳解的问题状态, 要不断地利用限界函数(bounding function)来处死那些实 际上不可能产生所需解的活结点,以减少问题的计算量。 具有限界函数的深度优先生成法称为回溯法
回溯法
回溯算法是所有搜索算法中最为基本的一种算法,是一 种能避免不必要搜索的穷举式的搜索算法,其基本思想 就是穷举搜索。 搜索的方式 主要采用深度优先搜索的方式 回溯三要素: 1) 解空间:该空包含问题的解 2) 约束条件 3) 状态树
问题的解空间
•问题的解向量:回溯法希望一个问题的解能够表示成一个n元式(x1,x2,„,xn) 的形式。 •显约束:对分量xi的取值限定。 •隐约束:为满足问题的解而对不同分量之间施加的约束。 •解空间:对于问题的一个实例,解向量满足显式约束条件的所有多元组,构成 了该实例的一个解空间。
跳马问题
分析: 按题意,马每一步可以有4种走法!
搜索过程: 1. 当马一开始位于左下角的时候,根据规 则,它只有两条线路可以选择(另外两 条超出棋盘的范围),我们无法预知该 走哪条,故任意选择一条,到达A1。 2.当到达A1点后,又有三条线路可以 选 择,于是再任意选择一条,到达B1。 3.从B1再出发,又有两条线路可以选择, 先选一条,到达C1。
要素三:状态树
将搜索过程中的每个状态用树的形式表示出来! 画出状态树对书写程序有很大帮助!
K=0
过程:进入新一行, 该行上按顺序逐个 格子尝试,直到能 放为止(不冲突、 不越界)
N皇后问题
* **
算法描述: 1. 产生一种新放法 2. 冲突,继续找,直到找到不冲 突----不超范围 3. if 不冲突 then k<nk+1 k=n一组解 4. if 冲突 then 回溯
回溯
Backtracking
回溯 N皇后问题 跳马问题 迷宫问题 图的着色问题 0-1背包问题 装载问题 批处理作业调度 填数问题 组合输出问题 算24点问题 ACM应用
学习要点
掌握回溯Fra Baidu bibliotek概念 掌握经典问题的回溯解决方法 掌握回溯与其它方法的异同
回溯法
有许多问题,当需要找出它的解集或者要求回答什么 解是满足某些约束条件的最佳解时,往往要使用回溯 法。 ► 回溯法的基本做法是搜索,或是一种组织得井井有条 的,能避免不必要搜索的穷举式搜索法。这种方法适 用于解一些组合数相当大的问题。 ► 回溯法在问题的解空间树中,按深度优先策略,从根 结点出发搜索解空间树。算法搜索至解空间树的任意 一点时,先判断该结点是否包含问题的解。如果肯定 不包含,则跳过对该结点为根的子树的搜索,逐层向 其祖先结点回溯;否则,进入该子树,继续按深度优 先策略搜索。
迭代回溯
采用树的非递归深度优先遍历算法,可将回溯法表示为一个非 递归迭代过程。
void iterativeBacktrack () { int t=1; while (t>0) { if (f(n,t)<=g(n,t)) for (int i=f(n,t);i<=g(n,t);i++) { x[t]=h(i); if (constraint(t)&&bound(t)) { if (solution(t)) output(x); else t++;} } else t--; } }
N皇后问题
递归写法: procedure try(k:byte); var i:byte; begin for i:=1 to n do if place(k) then begin x[k]:=i; if k=n then print else try(k+1); end;
分析:状态恢复(回溯)在什 么地方实现?
►
回溯法
回溯算法是所有搜索算法中最为基本的一种算法,是一 种能避免不必要搜索的穷举式的搜索算法,其基本思想 就是穷举搜索。 算法思想: 采用了一种“走不通就掉头”的思想。搜索时往往有多分支, 按某一分支为新的出发点,继续向下探索,当所有可能情况都 探索过且都无法到达目标的时候,再回退到上一个出发点,继 续探索另一个可能情况,这种不断回头寻找目标的方法称为 “回溯法”。
A2 A1 A B3 A2 A1 B2 C2 B1 C1
A
跳马问题
4. 从C1出发,可以有三条路径,选择D1。 但到了D1以后,我们无路可走且D1也不 是最终目标点,因此,选择D1是错误的, D3 B3 我们退回C1重新选择D2。同样D2也是错 B2 C2 误的。再回到C1选择D3。D3只可以到E1, A2 但E1也是错误的。返回D3后,没有其他 C1 A1 B1 选择,说明D3也是错误的,再回到C1。 A 此时C1不再有其他选择,故C1也是错误 的,退回B1,选择C2进行尝试。
④
③ ② ①
⑤
⑤ ⑥
④
② ① ③
Path[5]:=1
④
⑤ ⑥
⑤ ⑥
⑦
⑤
⑤
跳马问题
跳马问题(非递归)
Horse() begin path[1] ← 0,k ← 1,x ←1,y ←1 while (x<>m) and (y<>n) do begin path[k] ←path[k] +1 while (x + dx[i] <= n) and (y + dy[i] > 0) and (y + dy[i] <= n) and (path[k]<=4) do path[k] ← path[k] +1 if path[k]<=4 then {在4种走法中找到不越界的走法} begin x ←x+dx[i],y ←y+dy[i] if (x<>m) and (y<>n) then print else begin k ← k+1 path[k] ← 0 end end else path[k] ← 0,k ← k-1 end end
从上面的分析我们可以得知: 在无法确定走哪条线路的时候,任选一条线路 进行尝试;为方便路径表示,对马可以走到的四个 点(方向)都编上号; 当从某点出发,所有可能到达的点都不能到达 终点时,说明此点是一个死节点,必须回溯到上一 个点,并重新选择一条新的线路进行尝试。
y
④
③
②
解空间:
①
为了描述路径,我们最直接的方法就是记录路径上所有点的坐标。 优化:每一个方向上两个坐标和原位置对应关系 增量数组: 若马所处的位置为 (x,y),则其下一步可以 dx = (1, 2, 2, 1) 到达的四个位置分别是 (x+1, y-2), (x+2, dy = (-2, -1, 1, 2) y-1),(x+2, y+1),(x+1, y+2)。
x
path:array[1..m] of integer; 其中,path[i]:表示第i个节点所走的方向
方向t,下一步的位置就是 (x+dx[t], y+dy[t])。
跳马问题
约束条件:
不越界: (x + dx[i] <= n) and (y + dy[i] > 0) and (y + dy[i] <= n)
回溯法的基本思想
(1)针对所给问题,定义问题的解空间; (2)确定易于搜索的解空间结构; (3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数 避免无效搜索。
常用剪枝函数: 用约束函数在扩展结点处剪去不满足约束的子树; 用限界函数剪去得不到最优解的子树。
用回溯法解题的一个显著特征是在搜索过程中动态产生问题的 解空间。在任何时刻,算法只保存从根结点到当前扩展结点的 路径。如果解空间树中从根结点到叶结点的最长路径的长度为 h(n),则回溯法所需的计算空间通常为O(h(n))。而显式地存储 整个解空间则需要O(2h(n))或O(h(n)!)内存空间。
{每层均有n种放法} {寻找放置皇后的位置}
{放置皇后) {8个皇后都放置好,输出} {若只想找一组解,halt} {继续递归放置下一个皇后}
end;
跳马问题
在n×m棋盘上有一中国象棋中的马: 1. 马走日字; 2. 马只能往右走。 请你找出一条可行路径,使得马可以从棋盘的左下角(1,1)走 到右上角(n,m)。 输入:9 5 输出:(1,1)->(3,2)->(5,1)->(6,3)->(7,1)->(8,3)->(9,5)
状态树:
0
Path[1]:=3 Path[2]:=2 Path[3]:=3
①
②
4
③
④
Path[4]:=2 3 4
④ ⑤
算法描述: 1. 产生一种新走法 2. 越界,继续用新走法,直到找 到一种走法不越界----不超过4 种走法 3. if 不越界 then k<nk+1 k=n一组解 4. if 越界 then 回溯 ⑦
递归回溯
回溯法对解空间作深度优先搜索,因此,在一般情况下用递 归方法实现回溯法。
void backtrack (int t) { if (t>n) output(x); else for (int i=f(n,t);i<=g(n,t);i++) { x[t]=h(i); if (constraint(t)&&bound(t)) backtrack(t+1); } }
回溯部份: 即状态恢复,使其恢复到进 入该分支前的状态,继续新的 分支 x[k]:=0; Dec(k);
程序实现: 回溯算法可用非递归和递归两种方法实现!
N皇后问题
非递归写法: 算法描述: Nqueens() 1. 产生一种新放法 begin 2. 冲突,继续找,直到找到不冲 Flag ← true x[1] ← 0 突----不超范围 3. if 不冲突 then k<nk+1 k←1 k=n一组解 while k>0 do While flag do 4. if 冲突 then 回溯 begin x[k] ← x[k] +1 while x[k]<=n and (not place(k)) do x[k] ← x[k] +1 if x[k]<=n then if k=n then sum ← sum+1 if k=n then print;flag ←false else begin k ← k+1 x[k] ← 0 end else k ← k-1 end end
D2 E1 D1
5. 从C2出发,有四条路径可以选择,选择 D4,从D4出发又有两条路径,选择E1错 误,返回D4选择E2,从E2出发有两条路 径,先选择F1错误,返回E2选择B,而B 恰好是我们要到达的目标点,至此,一 条路径查找成功。
B3 A2 B2 C2 A1 B1 D4 E2
B
A
E1 F1
跳马问题
K=1
K=2
* * *** * *
回溯
*
*
出解后 可以继 续刚才 的做法
K=3
* * * * ** * * * * * * * * * * *
回溯
*
*
* *
*
K=4
* *
*
N皇后问题
程序结束条件: 一组解:设标志,找到一解后更改标志,以标志做为结束循环的条 件所有解:k=0
判断约束函数 Function Place(k:integer):boolean; place:=true; for j←1 to k-1 do if |k-j|=|x[j]-x[k]| or x[j]=x[k] then place:= false
x[3,1,4,2]
N皇后问题
要素二:约束条件
不同行:数组x的下标保证不重复 不同列:x[i]<>x[j] (i<=I,j<=n;i<>j) 不同对角线: abs(x[i]-x[j])<>abs(i-j)
填到第K行时,就与前1~(K-1)行都进行比较
Function Place(k:integer):boolean; place:=true; for j←1 to k-1 do if |k-j|=|x[j]-x[k]| or x[j]=x[k] then place:= false