当前位置:文档之家› 回溯算法

回溯算法


刚才的方法为生成皇后的摆放方案再去判断是否符合 要求,效率比较低,我们能不能每摆放一个皇后就看 这个皇后摆放的位置对还是不对,这样可以节省很多 无效的搜索 procedure try(dep:longint); var i:longint; begin if dep>n then inc(total) else for i:=1 to n do begin a[dep]:=i; if pd(dep) then try(dep+1); end; end;
procedure search(dep:longint); var i:longint; begin if dep>n then print else for i:=1 to 4 do{每个城市有四种颜色} begin a[dep]:=i; if check(dep) then search(dep+1); end; end;
主要代码: procedure search(dep:longint); var i:longint; begin if dep>n then print else for i:=1 to n do begin a[dep]:=i; search(dep+1); end; end;
program pailie(input,output); var n:integer; a:array[1..20] of integer; procedure print; var i:integer; begin for i:=1 to n do write(a[i]); writeln; end;
代码实现: procedure try(dep:longint); var i:longint; begin if dep>n then print else for i:=1 to n do begin a[dep]:=i; try(dep+1); end; end;
过程print 为打印方案,打印方案前需要判断此方案是否有冲突
递归回溯 定义一个手工栈记录递归调用前及回溯时的断点; procedure Search(dep:integer); begin if 当前是目标状态 then 输出解或者做计数、评价处理 else for i:=1 to 状态的拓展可能数 do if 第i种状态拓展可行 then begin 保存现场(断点,维护参数表); Search(dep+1); 恢复现场(回溯,回到上一个断点继续执行); end; end;
23
以4皇后为例:
24
function pd(i:longint):boolean;
var j:longint; begin pd:=true;
for j:=1 to i-1 do
if (a[i]=a[j])or (a[i]-a[j]=i-j)or (a[i]-a[j]=j-i)
then begin pd:=false; end;
回溯算法
——2016冬令营第4讲
1
迷宫游戏
入口 回溯
回溯 回溯
回溯
出口
搜索算法
对某些问题建立数学模型时,即使有一 定的数学模型,但采用数学方法解决有一定 的困难。对于这一类试题,我们用模拟或搜 索求解。 在缺乏解决问题的有效模型时,搜索却是一 种行之有效的解决问题的基本方法。 枚举法(穷举法) 深度优先搜索(回溯法) 广度优先搜索
pd为判断第dep 个皇后放在i的位置是否合适,如果合适再摆 放后一个皇后如果不合适,则第dep个皇后选择另一个方案。
二、如何判断第dep行的皇后能不能放在第i列:
function pd(i:longint):boolean; var j:longint; begin pd:=true; for j:=1 to i-1 do if (a[i]=a[j])or (a[i]-a[j]=i-j)or (a[i]-a[j]=j-i) then begin pd:=false; end; end;
f[i] := TRUE dfs(g + 1) f[i] := FALSE;
f[1] := TRUE dfs( 2) f[1] := FALSE; f[2] := TRUE dfs(3) f[2] := FALSE; f[3] := TRUE dfs(4) f[3] := FALSE;
例2:n皇后问题 在n×n的国际象棋棋盘上,放置n个 皇后,使任何一个皇后都不能吃掉另一个, 需满足的条件是:同一行、同一列、同一 对角线上只能有一个皇后。求所有满足要 求的放置方案。
check为检查当前城市填的颜色是否可行
function check(dep:longint):boolean; var i:longint; begin check:=true; for i:=1 to dep-1 do if (map[dep,i]=1)and(a[dep]=a[i]) then check:= false; end;
;
如果我们不考虑错误的方案数字,那么 摆放4皇后的所有方案就成为: 1111 1112 1113 1114 1121 1122 1123 ....4444 就转成了全排问题。 n皇后问题就转换为n个数字的全排, 只需把符合要求的方案挑选出来就行了, 那么此问题就可以转换为生成n个数字的 全排,我们可以利用回溯法来实现。
5
迷宫游戏
入口
方向: 上 次序: 4
下 左 1 3
右 2
2 3 -1
1 1 1 2 1 1 1 2 2 1 1 31 -12 1
出口
回溯法是搜索算法中的一种控制策略, 它是从初始状态出发,运用题目给出的条 件、规则,按照深度优先搜索的顺序扩展 所有可能情况,从中找出满足题意要求的 解答。回溯法是求解特殊型计数题或较复 杂的枚举题中使用频率最高的一种算法。
例3:四色问题
在有一张包含N(N≤10)块区域的地图,给出M(M≤50) 个描述,每组描述A,B表示A,B相邻,相邻的区域不能染 同一种颜色,一种有四种颜色,请你用这四种颜色给地图染 色,一共有多少中染色方法?
Input 第一行两个数N和M
Sample Input 54
接下来M行,每行一组数A,B
3.1.3 回溯法解决n皇后问题

















【分析】
一、问题解的形式: a:array [1..n] of integer; a[i]:第a[i]列,保证所有皇后不同行(第i个皇后 放在第i行) 问题的解变成求(a[1],a[2],…,a[n]) 4皇后问题的解: (2,4,1,3), (3,1,4,2)
思考1
想输出 111 112 113 121 122 123 131 132 133 211 212 213 221 222 223 231 232 233 311 312 313 321 322 323 331 332 333
10
思考2
输出 1111 1112 1113 1114 1121 1122 1123 1124 1131 1132 1133 1134 1141 1142 1143 1144 1211 1212 ...... 4444 又该如何输出?
DFS算法框架1——直接递归 procedure Search(dep:integer,参数表); //需要时还可以自定义一些参数; begin if 当前是目标状态 then 输出解或者做计数、评价处理 else for i:=1 to 状态的拓展可能数 do if 第i种状态拓展可行 then begin //维护自定义参数; Search(dep+1,参数表); end; end;
procedure search(dep:longint); var i:longint; begin if dep>n then print else for i:=1 to n do begin a[dep]:=i; search(dep+1); end; end; begin readln(n); search(1); end.
表示A,B相邻 Output
12
13 14 15 Sample Output
32
一个数表示染色方法数
324
分析: 我们一次从第一个城市开始染色,接着第二 ,第 三……每个城市有四种颜色可供选择,每次在染色的 时候只需考虑已经染好色的城市跟当前城市相邻且为 同一种颜色则不符合要求,否则就染好色并进入下一 个城市染色。 5个城市不考虑不符合要求的染色方案,所有染色方 案为 11111 11112 11113 ...... 55555 此题又可转换为全排形式。利用回溯来实现。
进一步思考
全排列:输入n输出1..n个数的全部排列 (数字不重复) 1~3的全排列
123 132 213 231 312 321 6
Procedure dfs(g : Integer); { 递归过程 g 为当前深度 } Var i : Integer; Begin If (g > n)Then Begin For j := 1 To n Do { 输出一个排列方案 } Write(a[j], ' '); Writeln; { 每个方案 1 行 } Inc(tot); { 总数加 1, 等价于 tot := tot + 1; } End; For i := 1 To n Do { 枚举第 g 层应排的数 } If not f[i] Then { 如果 i 没有排列过 } Begin f[i] := TRUE; { 标志数组赋为已排列 } a[g] := i; { 第 g 层用 i} dfs(g + 1); { 继续枚举第g+1层} f[i] := FALSE; { 回溯,标志数组还原 } End; End;
相关主题