深度优先搜索实质上是图算法中的一种,其简要过程是:从顶点开始,对每个可以访问到的分支路径进行访问,直到不能继续往下深入为止,并且每个结点只访问一次
简而言之:深搜(也叫回溯法)采用的是“一直往下走,走不通了就掉头,换一条路再往下走”。
深度优先搜索的简要步骤:
1:访问顶点v
2:从顶点v开始,对未访问过的v的邻接点开始,对图进行深度优先遍历。直到图中有路径相通的顶点都被访问过为止。
事实上,这个步骤是一个递归步骤:访问了v之后,对v未访问的邻接点进行访问(此时该邻接点相当于之前的顶点v,再继续重复这个过程)
深度优先搜索的实质就是穷举,按照一定的顺序和规则不断地去尝试,直到找到问题的解。
对于一个问题的第一个状态叫做初始状态,最后要求的状态叫做目的状态。
在搜索的过程中,对当前状态进行检测,如果当前状态满足目的状态,那么这个当前状态就是结果之一。
深度优先搜索用一个数组存放产生的所有状态。
(1) 把初始状态放入数组中,设为当前状态;
(2) 扩展当前的状态,产生一个新的状态放入数组中,同时把新产生的状态设为当前状态;
(3) 判断当前状态是否和前面的重复,如果重复则回到上一个状态,产生它的另一状态;
(4) 判断当前状态是否为目标状态,如果是目标,则找到一个解答,结束算法。
(5) 如果数组为空,说明无解。
说了这么干话,来举几个例子:
最经典的深搜例题:走迷宫:
nyoj上的最少步数:
http://acm.nyist.net/JudgeOnline/problem.php?pid=58
题目描述:
这有一个迷宫,有0~8行和0~8列:
1,1,1,1,1,1,1,1,1
1,0,0,1,0,0,1,0,1
1,0,0,1,1,0,0,0,1
1,0,1,0,1,1,0,1,1
1,0,0,0,0,1,0,0,1
1,1,0,1,0,1,0,0,1
1,1,0,1,0,1,0,0,1
1,1,0,1,0,0,0,0,1
1,1,1,1,1,1,1,1,1
0表示道路,1表示墙。
现在输入一个道路的坐标作为起点,再如输入一个道路的坐标作为终点,问最少走几步才能从起点到达终点?
(注:一步是指从一坐标点走到其上下左右相邻坐标点,如:从(3,1)到(4,1)。)
输入
第一行输入一个整数n(0
输出
输出最少走几步。
样例输入
2
3 1 5 7
3 1 6 7
样例输出
12
11
分析:要从起点找到终点,有很多条路,那么可以用深搜的方法来找出所有的路。把每次走到终点的路长与最小长度minx进行比较,如果长度比minx还要小的话,就更新minx,minx的初始值是0x3fff;
#include using namespace std; #include //可以用到memset #include int map[9][9] = { 1,1,1,1,1,1,1,1,1, 1,0,0,1,0,0,1,0,1, 1,0,0,1,1,0,0,0,1, 1,0,1,0,1,1,0,1,1, 1,0,0,0,0,1,0,0,1, 1,1,0,1,0,1,0,0,1, 1,1,0,1,0,1,0,0,1, 1,1,0,1,0,0,0,0,1, 1,1,1,1,1,1,1,1,1 } ; struct point{//坐标的结构体声明 int x; int y; }; int dir[4][2] = {-1,0,0,1,1,0,0,-1}; vector v; int minx = 0x3fff; bool notRepeat(point x) { for (int i = 0; i < v.size(); ++i) { if (x.x==v[i].x&&x.y==v[i].y) { return false; } } return true; } void dfs(point a, point b) { if (a.x == b.x && a.y == b.y) { //结束搜索 if (v.size() < minx) { minx = v.size(); } return ; } else { for (int i = 0; i < 4; ++i) { point t; t.x = a.x+dir[i][0]; t.y = a.y+dir[i][1]; if (notRepeat(t) && !map[t.x][t.y] && t.x>=0 && t.y>=0 && t.x> n; point start;//起点 point finish; while (n--) { cin >> start.x >> start.y >> finish.x >> finish.y; v.push_back(start); dfs(start, finish); v.pop_back(); cout << minx-1 << endl; minx = 0x3fff; } return 0; }
这道题写完可以明显的发现,深搜有个很明显的特点:出来混都是要还的,所有用过的标记和坐标,在用完之后都需要还原。