搜索与回溯课件

上传人:我*** 文档编号:144715758 上传时间:2020-09-13 格式:PPT 页数:47 大小:1.26MB
返回 下载 相关 举报
搜索与回溯课件_第1页
第1页 / 共47页
搜索与回溯课件_第2页
第2页 / 共47页
搜索与回溯课件_第3页
第3页 / 共47页
搜索与回溯课件_第4页
第4页 / 共47页
搜索与回溯课件_第5页
第5页 / 共47页
点击查看更多>>
资源描述

《搜索与回溯课件》由会员分享,可在线阅读,更多相关《搜索与回溯课件(47页珍藏版)》请在金锄头文库上搜索。

1、搜索与回溯,东营市胜利第一中学 孙猛,对于某个问题,如果没有高效的算法,或者用高效的算法解决有一定的困难,我们常用搜索算法来求解,即通过枚举每一种可行的方案来找到题目的答案。,深度优先搜索,只要当前枚举到的状态可行,就继续枚举下去。当找到一种方案或者无法继续枚举下去时,就退回到上一状态。退回到上一状态的过程叫做回溯。,给定n(n10),求1,2,3,n的全排列个数。,如果一个数列含包含这n个数,并且这n个数都仅出现一次,符合该条件的所有数列叫做这n个数的全排列。,如1,2,3三个元素的全排列为: 1,2,3 1,3,2 2,1,3 2,3,1 3,1,2 3,2,1,看一个简单的问题,什么是全

2、排列?,先确定放在第1个位置的是哪个数,当n个位置的数都确定下来后,我们就得到了一个方案,依次确定第2个位置,第3个位置,第n个位置,我们可以用一个布尔数组used来表示每个数字是否用过,用过为true,未用过为false。用ansi记录第i个位置的数是多少,for i:=1 to n do if not usedi then /若i未出现过则在 第k个位置放i begin usedi:=true; /标记 ansk:=i; dfs(k+1);/继续搜索 usedi:=false;/回溯 end; end; begin read(n); dfs(1); end.,program quanpai

3、lie; var n:longint; ans:array 0.10 of longint; used:array 0.10 of boolean; procedure dfs(k:longint); var i:longint; begin if kn then begin for i:=1 to n-1 do write(ansi, ); writeln(ansn); exit; end;,A,B,枚举每种选择 if 该选择可行 then begin 更改该选择标记 dfs(k+1,); 回溯 end; end;,深度优先搜索的一般框架: Procedure dfs(k,); var be

4、gin if 已找到一种方案 then begin print; exit; end;,A,B,for j:=1 to n do if canj then begin canj:=false; ansi:=aj; dfs(i+1); canj:=true; end; end; begin read(n,k); for i:=1 to n do read(ai); fillchar(can,sizeof(can),true); dfs(1); writeln(s div n); end.,program P1085; var s,i,j,k,m,n:longint; ans,a:array 0.

5、10 of longint; can:array 0.10 of boolean; procedure dfs(i:longint); var j:longint; f:boolean; begin if in then begin f:=true; for j:=1 to n-1 do if abs(ansj-ansj+1)k then begin f:=false; break; end;/检验1与2,n-1与n if f and (abs(ansn-ans1)=k) then inc(s); exit; end;,A,B,有没有更好的做法? 我们发现,当我们确定下第一个位置的人与第二个位

6、置的人时,他们的身高可能已经不符合要求了,但我们仍然搜索了下去。我们可以一边搜索一边判断。,for j:=1 to n do if canj and (abs(aj-ansi-1)=k) then /若第j个人还没有确定位置 并且和上一个人符合要求 begin canj:=false;/标记 ansi:=aj; dfs(i+1);/继续搜索 canj:=true;/回溯 end; end; begin read(n,k); for i:=1 to n do read(ai); fillchar(can,sizeof(can),true); ans1:=a1;/将第一个人位置固定 can1:=f

7、alse;/更改标记 dfs(2); writeln(s); end.,program P1085; var s,i,k,n:longint; can:array 0.10 of boolean; a,ans:array 0.10 of longint; procedure dfs(i:longint); var j:longint; begin if in then begin if abs(ansn-ans1)=k then inc(s); exit; end;,A,B,下表给出了一个可行的方案,我们可以依次确定每一行皇后的位置,如果在某一列可以放下一个皇后,我们就在这里放下,并搜索下一行

8、,若无法放下皇后则回到上一行,即回溯,当n行的皇后都已确定后,我们就找到了一种方案,如何判断某行某列能否放皇后?,该行能否放?,按行搜索,保证每一行放一个皇后,用布尔数组标记某列能否放,该列能否放?,对角线能否放?,对角线上的点和或差相同,也可用布尔数组标记,问题已解决!,begin aj:=false; bi+j:=false; ci-j:=false; dfs(i+1); aj:=true; bi+j:=true; ci-j:=true; end; end; begin fillchar(a,sizeof(a),true); fillchar(b,sizeof(b),true); fill

9、char(c,sizeof(c),true); readln(n); ans:=0; dfs(1); writeln(ans); end.,program bahuanghou; var k,n,ans:longint; a,b,c:array -100.100 of boolean; f:array 0.100 of longint; procedure dfs(i:longint); var j:longint; begin if in then begin inc(ans); exit; end; for j:=1 to n do if ajand bi+jand ci-jthen,A,

10、B,你有n堆石头质量分别为W1,W2,Wn(W100 000)。现在需要你将石头合并为两部分,使两部分的质量之和最接近。,输入:第一行为整数n(1n20),表示有n堆石子。第二行n个整数,为每堆石子的质量。,输出:一行。只需要输出合并后两部分的质量之和的差。,样例输入: 样例输出: 5 3 5 8 13 27 14,石子合并,begin ans:=maxlongint; sum:=0; read(n); for i:=1 to n do begin read(wi); sum:=sum+wi; end; dfs(1,0); writeln(ans); end.,program shiziheb

11、ing; var ans,sum,i,j,k,n:longint; w:array 0.20 of longint; function min(a,b:longint):longint; begin if ab then exit(b) else exit(a); end; procedure dfs(k,tot:longint); begin if (tot*2=sum)or(kn) then begin ans:=min(ans,abs(sum-tot-tot); exit; end; dfs(k+1,tot+wk); /将第k堆石子并入第一部分 dfs(k+1,tot); /将第k堆石子

12、并入第二部分 end;,A,B,自然数拆分,输入自然数n,然后将其拆分成由若干数相加的形式,参与加法运算的数可以重复。,输入只有一个整数n,表示待拆分的自然数n。 n=80 输出一个数,即所有方案数 1+2与2+1算一种方案,时间限制 1s 样例输入 7 样例输出 14,输入7,则7拆分的结果是 7=1+6 7=1+1+5 7=1+1+1+4 7=1+1+1+1+3 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 7=1+1+1+2+2 7=1+1+2+3 7=1+2+4 7=1+2+2+2 7=1+3+3 7=2+5 7=2+2+3 7=3+4 一共有14种情况,所以输出14,我

13、们可以枚举一个数,用n减去这个数,再枚举一个数,再减去这个数,直至减到0,我们就找到了一种方案。 但是这样做会有重复,即对于3我们会先减1再减2,也会先减2再减1,该如何避免重复? 我们可以在搜索的时候可以记录一个变量last,表示上次减掉的是哪个数,我们只允许减小于等于last的数,这样可以避免重复。,begin read(n); dfs(n,n); s:=s-1; /因为我们把n=n也算作 了一种方案,所以方案数要减一 writeln(s); end.,program P1171; var i,j,k,n,s:longint; procedure dfs(last,tot:longint)

14、; var i:longint; begin if tot=0 then begin inc(s); exit; end; for i:=last downto 1 do if tot-i=0 then dfs(i,tot-i); end;,A,B,NOIP2009靶形数独,有一个未填满的数独,求这个数独填满后能获得的最大总分数 分数计算方法:,总分数为每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和,时间限制 2s 样例输入 7 0 0 9 0 0 0 0 11 0 0 0 0 5 9 0 00 0 0 2 0 0 0 8 00 0 5 0 2 0 0 0 30 0 0 0 0

15、 0 6 4 84 1 3 0 0 0 0 0 00 0 7 0 0 2 0 9 02 0 1 0 6 0 8 0 40 8 0 5 0 4 0 1 2 样例输出 2829,一个最简单的想法: 我们可以从左上角到右下角枚举每一个未填上的格子,再枚举它可以放哪些数字,将它填上后继续搜索。当所有格子都填上后,计算一下总分,如果总分大于当前最优值就更新最优值 这样大约可以得35分,我们还可以对上面的想法进行改进: 我们可以先计算出每个格子的选择数 先确定可选择数小的格子 即先把只有一种选择的格子确定下来 再确定有两种选择的格子 从而避免搜索到过多无法得到可行方案的状态 这样大约可以得75分,对于这道题,由于数据的原因,如果从右下角到左上角枚举,可以得到90分左右。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > PPT模板库 > PPT素材/模板

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号