深度优先搜索(DFS):
是一种搜索手段。可以理解为:它从某个位置(起点)开始,沿着一条路不断地向前走直到尽头,然后退后一步,去走其它没走过的路,没有的话,再退后一步,再去选择,直到找到目的地(终点)。
例如下图:
从A(起点)开始走,先走ABD
在D处发现没有子节点,推后到节点B,去走EG
到节点G发现又到了尽头,然后退一步到节点E,发现节点E没有右节点
再退到节点B,发现B的左右节点都走过了,再退到节点A,去走AC
节点C没有左子树,走右子树F,F是尽头,退到C,退到A,返回。
适用场景:
有三个方面,分别是输入数据、状态转换图、求解目标;
输入数据:如果是递归数据结构,如单链表,二叉树,集合,则百分之百可以使用深搜;如果是非递归数据结构,比如一维数组、二维数组、字符串、图,则概率要小一些;
状态转换图:树或者图;
输入数据:必须要走到最深(比如对于树,必须要走到叶子结点)才能得到一个解,这种情况比较适合用深搜;
例题1:
给定整数a1,a2.....an,判断是否可以从中选出若干数,使他们的和恰好为k。
(限制条件:1<=n<=20,-108<=108,-108<=k<=108)
简单的DFS运用,每个数据都用两种选择:加上或者不加,时间复杂度:2n。
代码:
#define MAX_N 1005
int data[MAX_N];
int n,k;
// 从前i项得到的和sum
bool DFS(int i,int sum)
{
// n项都计算过了,判断是否等于k
if(i == n)
return sum == k;
// 不加上第i项
if(DFS(i+1,sum))
return true;
// 加上第i项
if(DFS(i+1,sum+data[i]))
return true;
return false;
}
结果:
嗯,一个简单的小例子,就算是比赛一般也就大一前3题吧。
例题2:
有一个大小为N * M的院子,雨后积起了水。‘W’代表积水,'.'代表没有积水。八连通的积水被认为是连接在一起的。请求出院子里总共有多少水洼?(限制条件:N,M<=100)
(八连通表示:上,下,左,右,左上,左下,右上,右下都属于直接连通。下图相对于W的*部分)
* * *
*W*
* * *
代码:
#define MAX_N 100
int N,M;
int Map[100][100];
void DFS(int x,int y)
{
Map[x][y] = '.'; // 判断过的位置变为'.'没有积水
// 判断连通的八个位置
for(int dx=-1;dx<=1;dx++)
for(int dy=-1;dy<=1;dy++)
{
int Nx = x + dx;
int Ny = y + dy;
if(Map[Nx][Ny] == 'W' && Nx>=0 && Nx<N && Ny>=0 && Ny<M)
DFS(Nx,Ny);
}
return ;
}
int Solve()
{
int Ans = 0;
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
{
if(Map[i][j] == 'W')
{
// 每一次走入该判断中,代表新增一个水洼,同时把该水洼所有的'W'全改为'.'
Ans++;
DFS(i,j);
}
}
return Ans;
}
结果:
测试的数据:
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
一会儿会更新BFS,最近看动态规划有点迷惑,可能会晚一些。