目前在学习 DFS BFS 回溯 递归 及剪枝 ----> 等算法,观看了好多博主的博客 自己总结一下:
递归::简单来说就是自己调用自己,循环下去知道 条件满足,返回条件的数据。
优点: 结构简单
缺点: 效率不高 ,可能会栈溢出
一般形式::
void dfs()
{
if(符合边界条件)
{
******
return *;
}
***
dfs();
}
回溯:是递归的一种,是通过用递归来实现的回溯目的,回溯也可以认为是剪枝的DFS过程。
从树的角度:带回溯的DFS遍历一棵解答树
代码结构::
void dfs(int 当前状态)
{
if(当前状态的边界条件)
{
记录数据或者输出
return *;
}
for(int i=0; i<n; i++)//横向遍历解答树所有子节点
{
// 扩展出一个子状态。
if(子状态满足约束条件)
dfs();
恢复全局变量// 回溯部分
}
}
** BFS和DFS相似**
BFS (显示用队列)
DFS (隐试用队列 ->递归)
BFS:::
将(起始)首节点加入队列:
q.push(head);
标记首节点已经被访问:
isvisited[head]=true;
以下自动反应:
while(!q.empty())
{
int temp=q.front();
q.pop();
访问temp,并标记temp已被访问过,
将temp的子相关节点加入列
q.push(temp相关节点);
}
**
DFS --------DFS 区别
**
BFS : 一层一层的遍历 ——用来求 最短路径
DFS :一条路走到黑 ——运用递归进行回溯遍历
BFS常用语找最短路径(路径没有权重,如果有权重的话 可以用Dijkstra 、bellman等):
BFS简单理解就是 一成一成的往下遍历,如果找到目标节点就是最短路,因为其他的路径最少起码再往下走一层或更多层才有可能到达,无疑比当前这条路径长如下fig1,从开始出发后,先在第一层中找,即1,2,3没有找到结束标记,接着从第二层中找4,5,6,7,8,9没有结束标记,接着从第三层找即10,11,12,end 哇!找到了,这时就可以结束了即最短路径就是start-2-6-end,为什么呢?因为尽管接着继续往下一层走还有可能有到达终点的路径类如(start-1-4-11-14-16-end),但层数增多了,路径增多了,我们要的是最短路径所以不给予考虑。注意,有可能同一层下有多条路径,这时候就最短路径有可能就是多条,类如fig2其实最短路径除了start-2-6-end还有start-3-8-end,但是如果要求只是找到一条最短路径,那么其实一旦找到一条就可以停止了,但如果是找到所有最短路径,务必把当前层遍历完才可结束。
如图所示:
大致步骤:(就是找到一条路就可以了)
1.首先将开始节点加入队列
2.取出首节点,判断当前节点是否为结束节点,是则结束while 返回需要信息,如果不不是进行操作3.
3.然后将当前对首节点相邻的(一步到达)所有节点依次放入队列中,放入时记录路径信息。(步数,该节点的父节点等等)。同时标记该节点为一访问过。
BFS 找最短路径模板::
void bfs(begin,end,list)
{
#1 将开始节点放入队列
queue=[(begin,1)]
listtemp=list
while queue:
temp,lens=queue.pop(0);
if( temp==end)
return list;
else
for newnode in tempNeighbourNodes;
#记录路径信息:最后遍历到一个就加入到队列里
queue。append(new node,lens+1)
listtemp.remove(newnode)
return 0;
}
二 来源于其他博主
DFS====
BFS
两者代码模板
BFS:
#include<cstdio>#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量
struct State // BFS 队列中的状态数据结构
{
int x,y; // 坐标位置
int Step_Counter; // 搜索步数统计器
};
State a[maxn];
bool CheckState(State s) // 约束条件检验
{
if(!vst[s.x][s.y] && ...) // 满足条件
return 1;
else // 约束条件冲突
return 0;
}
void bfs(State st)
{
queue <State> q; // BFS 队列
State now,next; // 定义2 个状态,当前和下一个
st.Step_Counter=0; // 计数器清零
q.push(st); // 入队
vst[st.x][st.y]=1; // 访问标记
while(!q.empty())
{
now=q.front(); // 取队首元素进行扩展
if(now==G) // 出现目标态,此时为Step_Counter 的最小值,可以退出即可
{
...... // 做相关处理
return;
}
for(int i=0;i<4;i++)
{
next.x=now.x+dir[i][0]; // 按照规则生成下一个状态
next.y=now.y+dir[i][1];
next.Step_Counter=now.Step_Counter+1; // 计数器加1
if(CheckState(next)) // 如果状态满足约束条件则入队
{
q.push(next);
vst[next.x][next.y]=1; //访问标记
}
}
q.pop(); // 队首元素出队
}
return;
}
DFS
/*
该DFS 框架以2D 坐标范围为例,来体现DFS 算法的实现思想。
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int map[maxn][maxn]; // 坐标范围
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量,(x,y)周围的四个方向
bool CheckEdge(int x,int y) // 边界条件和约束条件的判断
{
if(!vst[x][y] && ...) // 满足条件
return 1;
else // 与约束条件冲突
return 0;
}
void dfs(int x,int y)
{
vst[x][y]=1; // 标记该节点被访问过
if(map[x][y]==G) // 出现目标态G
{
...... // 做相应处理
return;
}
for(int i=0;i<4;i++)
{
if(CheckEdge(x+dir[i][0],y+dir[i][1])) // 按照规则生成下一个节点
dfs(x+dir[i][0],y+dir[i][1]);
}
return; // 没有下层搜索节点,回溯
}
int main()
{
.....
return 0;
}
***