算法入门——深搜(depth first search)小结

深度优先搜索实质上是图算法中的一种,其简要过程是:从顶点开始,对每个可以访问到的分支路径进行访问,直到不能继续往下深入为止,并且每个结点只访问一次

简而言之:深搜(也叫回溯法)采用的是“一直往下走,走不通了就掉头,换一条路再往下走”。

深度优先搜索的简要步骤:

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 随后n行,每行有四个整数a,b,c,d(0<=a,b,c,d<=8)分别表示起点的行、列,终点的行、列。

输出

输出最少走几步。

样例输入

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;
}

这道题写完可以明显的发现,深搜有个很明显的特点:出来混都是要还的,所有用过的标记和坐标,在用完之后都需要还原。

你可能感兴趣的:(C++,算法)