四、深度优先搜索
深度优先搜索会首先从一层探索到最深直到碰壁无法行走,在换另一条路搜索下去,用这个方法走遍所有的路,并且规定不会走重复的路。深度优先搜索的代码通常会比广度简便一些,但像最短距离之类的问题还是要使用广度优先搜索。
1 .与递归结合
深度优先搜索用递归实现是最普遍的,hdu1312的红黑砖块问题用dfs做就更为简便。
void dfs(int dx,int dy){
a[dx][dy]='#'; //标记已经走过
num++; //走过的砖块数+1
for(i=0;i<4;i++)
{ int nx=dx+dir[i][0]; //左上右下顺时针顺序搜索下一块砖块
int ny=dy+dir[i][1];
if(check(nx,ny)&&a[nx][ny]=='.') //如果在范围之内并且该砖块未走过,则用递归继续进行深度搜索
dfs(nx,ny);}
}
2.回溯与剪枝
为了防止路径过多而超时,很多子节点可以根据题目条件提前判断,中途停止并返回。
例:hdu 2553 n皇后问题
使棋子不同行、不同列、不同对角线,搜索的很多结点其实在开始就可以完成回溯,向不同行中插入棋子,只有不同列和不对角线的节点才可以继续延伸下去,依次可以构造回溯函数。
bool check(int c,int r)
{ for(i=0;i<r;i++)
{ if(a[i]==c||abs(a[i]-c)==abs(i-r)) return false;
else true;}
}
接下来构造向每一行中插入棋子的搜索函数dfs
void dfs(int r)
{ if(r==n) { total++; return;} //行满足所给n就可以结束单向搜索了
for(c=0;c<n;c++)
{ if(check(c,r){ //如果不满足回溯条件就可以继续搜索下去
a[r]=c; //及时更新列数
dfs(r+1);}
}
}
对于n皇后问题提前在主函数中打表就可以减小复杂度,避免超时。
3.迭代加深搜索
对于搜索树特别宽、特别深的类型不适用bfs和dfs,需要结合bfs和dfs的迭代加深搜索
迭代加深搜索就是提前设定搜索深度,在该搜索深度上进行dfs搜索,直到找到答案后停止搜索。
4.IDA*
A* 可以看作是bfs和贪心的结合,IDA*就可以看作是迭代加深搜索和贪心的结合,通过贪心思想提前预测到dfs的状态,也运用到了一部分的剪枝操作。
poj3134 计算x的n次方
通过题目理解可以构造相应的估价函数,不满足条件则要进行剪枝操作
if(val[p]<<(depth-now)<n) return false; //当前值倍增都不能达到n就要进行剪枝操作
通过前一步和所有值相加减进行搜索判断值是否等于n,通过设定深度搜索层数的方法加减求得答案,结束搜索。综上,运用迭代深度搜索和估价函数可以高效完成计算,大大减小复杂度。