首先自我介绍,我叫ZYF,来自广东中山(因孙中山而得名),是一个七年级的学生,目前在中山纪念中学学习信息学,主修Pascal,也会C++。
这是周报的新起点,我将会在每周定期更新,如有时间冲突也会补上,谢谢大家的支持。
这周我们来谈一谈最基础的入门算法——DFS。
想必DFS大家并非陌生,不管是背过模板还是做过题,都会或多或少了解DFS。但是我却对DFS有自己的看法与了解。
DFS,全名是深度优先搜索。顾名思义,它使用的是深度优先遍历。 深度优先搜索的过程是:
(1)访问顶点V
(2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
(3)如果有顶点尚未访问,会从当点重新进行深度优先遍历,直到所有点被遍历。
说了这么多干货,我们看几张图来了解过程:
这时上面的粉色部分,便是DFS极其重要的一步:回溯
回溯需要注意什么:
1.改变状态(否则会有答案错误),回到搜索前的状态。
2.改变参数,使DFS能正常结束。
听了这么多,是否了解DFS呢?
再来一点注意事项:一定要有结束条件!一定要有结束条件!一定要有结束条件!(重要的事情说三遍)
假如你没有结束条件,程序只会无休止的运行下去。
这是许多人会问:DFS这么慢,为什么要用呢?
1.DFS是某些正解算法的基础(比如DP),甚至能A掉某些题(但是数据会非常水)。
2.DFS可以拿到部分分(尤其是DP),假如没有想出正解或者不确定正解,可以用DFS拿到能拿的分。
3.许多题目加了剪枝就可以过(大多数是水过的),成为正解。
4.提高组常用的对拍,用来检测程序正确性。
一个简单的模板:
procedure search(参数表);
begin
if 到达目标
begin
更新答案;
退出;
end
else
begin
search(改变参数);
回溯;
end;
end;
当然,你也可以用数据结构存储参数,实现改变参数的目的。
例题:迷宫问题
题目大意:给你一个N*N的地图,某些点有障碍物,每次可沿点上下左右移动一格,求起点到终点的路径总数。
分析:一道经典的DFS题,深度优先遍历找到所有的路径,并统计答案。
参考程序:(抱歉我是P党)
const
ff:array[1..4,1..2]of longint=((1,0),(-1,0),(0,1),(0,-1));
var
x,y,ans,sx,sy,fx,fy,n,m,t,i:longint;
bz:array[-1..1000,-1..1000] of boolean;
function check(shu1,shu2:longint):boolean;
begin
if(shu1 in[1..n]) and(shu2 in[1..m]) then exit(true);
exit(false);
end;
procedure search(x,y:longint);
var
ii,xx,yy:longint;
begin
xx:=0;
yy:=0;
if (x=fx) and (y=fy) then
begin
ans:=ans+1;
exit;
end
else
begin
for ii:=1 to 4 do
begin
xx:=x+ff[ii,1];
yy:=y+ff[ii,2];
if check(xx,yy)=true then
begin
if bz[xx,yy]=false then
begin
bz[xx,yy]:=true;
search(xx,yy);
bz[xx,yy]:=false;
end;
end;
end;
end;
end;
begin
readln(n,m,t);
readln(sx,sy,fx,fy);
bz[sx,sy]:=true;
for i:=1 to t do
begin
readln(x,y);
bz[x,y]:=true;
end;
search(sx,sy);
writeln(ans);
end.
推荐例题:LG P1219 P1101 P1019 P1605 P1040 P1092 (试炼场链接:洛古试炼场)(题目在普及练习场2.7)
好了,本周周报就到此为止,下周的主题是:关于剪枝那些事。