搜索法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
主程序预处理和调用子程序
tot:=0;min:=maxint;b[1]:=1; try(1); writeln('tot=',min);
procedure try(i:integer); var k:integer; begin if i=n then begin if tot<min then min:=tot;exit;end else begin for k:=1 to n do if (b[k]=0) and (i<>k) and (a[i,k]<32700) then begin b[k]:=1;tot:=tot+a[i,k];try(k);b[k]:=0; tot:=tot-a[i,k]; end; end; end;
procedure try(I:integer);
var k:integer;
begin if 到达了终点 then
begin 保存较优解;返回上一点继续求解(回溯);end
else begin
穷举从I出发当前可以直接到达的点k;
if I到k点有直接联边 并且 k点没有遍历过 then then begin
procedure work_out_r(i1,ej:integer); var k:integer; begin for k:=0 to ej do begin f:=f+k*s[i1]; if i1=n then stamp:=stamp+[f] else work_out_r(i1+1,ej-k); f:=f-k*s[i1]; end; end;
输出子过程
procedure print; var i:integer; begin for i:=1 to n do if i<>n then write(a[i],' ') else writeln(a[n]); end;
深度搜索子过程
procedure try(i:integer); var j:integer; begin if i>n then print else for j:=1 to n do if not f[j] then begin a[i]:=j; f[j]:=true; try(i+1); f[j]:=false; end; end;
procedure try(i:integer); var j,temp,l:integer; begin for j:=s[i-1]+1 to m*s[i-1]+1 do begin s[i]:=j; if i=n then begin f:=0;stamp:=[]; work_out_r(1,m); temp:=1; while temp in stamp do temp:=temp+1; if rmax<temp-1 then for l:=1 to n do begin g[l]:=s[l];rmax:=temp-1;end; end else try(i+1); end; end;
Dfs的应用和优化
1、何时考虑用dfs? 2、适用的题型 3、出解的方式 4、优化策略
network
多台计算机相互连接,构成计算机网络。在这个问题中,我们只 考虑“线性”的网络:计算机首尾相连,构成一条计算机的链, 除了首尾2台计算机外,每台计算机恰与2台计算机相连。计算 机的物理位置可以用直角坐标表示。在施工时,电缆将被埋在地 下,因此连接网络中2台计算机所需的电缆长度等于他们之间的 距离再加上额外的16米,以便从地下连接到计算机,并为施工 留些余量。 出于经济、技术等方面的考虑,要求所使用的电缆总长度尽可能 地短。写一个程序,帮助寻找最优的网络连接方案。 输入和输出 输入文件的第一行是一个整数,表示计算机的总数。网络中包括 至少2台,至多10台的计算机。接下来的每一行将给出1台计算 机的横坐标和纵坐标,中间用空格隔开。坐标值是0到150的整 数。在一个坐标点上不会有2台计算机。 输出只有一行,给出你的程序所找到的最优连接方案所需电缆的 总长度。结果四舍五入保留2位小数。
输入文件: 6 5 19 55 28 38 101 28 62 111 84 43 116 输出文件: 305.45
主程序
readln(fin,n);min:=32650; for i:=1 to n do readln(fin,x[i],y[i]); close(fin); for i:=1 to n do b[i]:=0; s:=0;j:=1; for i:=1 to 6 do begin b[i]:=1; try(i,j); b[i]:=0; s:=0; end;
fruit.in 18 12340 2560 3780 4 9 10 0 5 11 12 0 6 13 0 7 14 15 0 80 90 10 16 0 11 17 0 12 0 13 0 14 0 15 0 16 0 17 18 0 18 0 2 5 30 6 3 22 29 28 10 11 4 9 24 33 8 21 7 1 fruit.out 94
算法分析
1、不能再用原来的穷举法 2、本题算法思考 (1)每个阶段指什么?各个阶段须完成什 么任务? (2)各个阶段试探的方案是什么?
主程序结构
var n:integer; a:array[1..9] of integer; f:array[1..9] of boolean; {用于记录是否重复} begin fillchar(f,sizeof(f),false); readln(n); try(1); end.
承上启下1
【例2】【题目描述】 列出所有从数字1到数字n的连续自然数的排列,要求所产生的 任一数字序列中不允许出现重复的数字。 【输入格式】 只有一个整数n(1≤n≤9) 【输出格式】 由1~n组成的所有不重复的数字序列,每行一个序列,数字之间用空 格隔开。 【输入样例】 3 【输出样例】 123 132 213 231 312 321
求同思维
想想原来邮票问题1是如何求解的?
1、穷举所有邮票可能的面值组合 2、进一步穷举每种邮票可能贴的数量 3、根据1、2的穷举计算当前方案可能的最 大连续r值 4、每产生一个r值后和原来rmax比较,保 存较优解
主程序
s[1]:=1;rmax:=0;f:=0; writeln; write('n,m='); readln(n,m); try(1); {首次调用过程,开始穷举邮票面值} for o:=1 to n do write(g[o]:4); {输出每种邮票的面值} writeln; writeln('rmax=',rmax);
递归子程序结构
if i=n+1 then begin 输出解;返回;end else for c:=’A’ to chr(64+m) do begin if c 可以放置 then begin 把c放置到位置 1上;try(i+1);状态恢复;end end;
承上启下2
【例4】邮票问题2。邮局发行一套有Βιβλιοθήκη Baidu种不 同面值的邮票,如果限制每封信所贴的邮 票张数不能超过m枚。存在整数R,使得 用不超过m枚的邮票可以贴出一下连续序 列:1,2,3,4,5,......,R。 编程求出可以得到尽可能大的R值以及对 应的n种邮票面值。
子程序
procedure try(i,j:byte); var k:integer; begin if j=n then begin if s<min then min:=s;exit;end else for k:=1 to n do if b[k]=0 then begin if s+f(i,k)>min then continue; s:=s+f(i,k); b[k]:=1; try(k,j+1); s:=s-f(i,k);b[k]:=0; end; end;
Procedure fruit(i:byte); j:=2; if a[i,j]=0 then begin if maxtot<tot then maxtot:=tot;exit;end else begin while a[i,j]<>0 do begin tot:=tot+w[a[i,j]];fruit(a[i,j]);tot:=tot-w[a[i,j]]; j:=j+1; end; end;
Dfs算法小结
1、dfs的算法思想 2、状态改变及现场保存 3、回溯处理及现场恢复 4、什么时候须进行回溯处理? 5、各个阶段当前须尝试的方案选择(第一 个方案开始?还是接着原来方案的下一个 方案?) 6、递归程序结构
递归结构框架
Procedure try(i:integer); Var k:integer; Begin If 所有阶段都已求解 then Begin 比较最优解并保存;回溯; end else begin 穷举当前阶段所有可能的决策(方案、结点)k if k方案可行 then begin 记录状态变化;try(i+1); 状态恢复(回溯); end end; End;
引题1
【例1】采摘果子。有如下图所示的一棵果 树,图中的结点表示树上的果子,结点左 边的数字表示结点的编号,里面的权值就 是果子的重量,现在果农想把某条树枝的 果子全部采摘下来,并保证被采摘果子的 总重量是所有树枝中最大的。问,这条树 枝上所有果子的总重量是多少?
输入文件fruit.in共包含了n+2行,其中 n表示图中果子的个数,第一行的一个整 数表示果树中果子的数量,第2-n行表示 各果子之间的连接关系(用邻接表表示), 最后一行依次表示了各个果子自身的重量, 用n个用空格隔开的整数。 输出文件fruit.out只包含一个整数,表示 某条树枝上所有果子的重量(是所有树枝 中果子总重量最大的那根树枝)。
{如果j没有被使用,则继续} {放入一个数j} {标记该数已经使用} {继续放下一个数} {回溯时重置使用标记}
引题2
【例4】选择最短路径。有如下所示的交通 路线图,边上数值表示该道路的长度,编 程求从1号地点到达7号地点的最短的路 径长度是多少,并输出这个长度。
与“引题1”不同的地方?
1、是一个显式图 2、权值是边权 3、需要判重处理
几近万能的算法
知识准备
1、分阶段决策 2、状态 3、方案 4、决策
了解深度优先搜索法
1、degree first serch 2、在每个阶段的决策时,采取能深则深的原则试 探所有可行的方案,一旦深入一层则保存当前操 作引起的状态 3、一旦试探失败,为了摆脱当前失败状态,采取 回到上一阶段尝试下一方案的策略(回溯策略); 或者在求解所有解时,求得一个解后,回溯到上 一阶段尝试下一方案,以求解下一个解 4、在各个阶段尝试方案时,采取的是穷举的思想
数据结构
1、邻接矩阵表示图的连接和权值。 A[I,j]=x,或者a[I,j]=maxint。B[i] 表示结点i是否已经遍历过 2、用变量min来保存最优解,而用tot变 量保存求解过程中临时解(当前路径总长 度)。 3、状态。Tot的值和结点的遍历标志值
程序结构
1、递归结构 2、主程序中用try(1)调用递归子程序 3、子程序结构
把A[I,K]累加入路径长度tot;k标记为已遍历;try(k);
现场恢复; end; end;
关键环节的分析
1、递归结束的判断 2、保存较优解的处理 3、各个阶段可试探方案的穷举和可行性判断
主程序数据输入
readln(fi,n); for i:=1 to n do begin for j:=1 to n do read(fi,a[i,j]); readln(fi); end; close(fi);
1、分析样例数据 2、样例数据如何来求解 3、穷举什么? 4、穷举实现的方式
1、A[1,3]=3表示1号结点的第2个儿子是3 号结点,A[I,1]表示结点本身。用一维数 组W表示每个结点的重量信息。 2、状态保存及继续深入。 tot:=tot+w[a[I,j]],继续往下搜索,用 语句fruit(a[I,j])来实现 3、回溯处理。tot:=tot-w[a[i,j]];为下一 次搜索作准备,就是inc(j)。
数据输入
for i:=1 to n do begin j:=0; repeat inc(j);read(fin,a[i,j]); until a[i,j]=0; readln(fin); end; for i:=1 to n do read(fin,w[i]);close(fin);
tot:=tot+w[1];fruit(1);