深搜广搜基本概念

一,深度优先搜索:
事实上,深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。

在这里插入图片描述
其实这就像是一棵树的前序遍历。它从某个顶点v出发,访问此顶点,然后从v的未被访问的领接点
出发深度优先遍历图, 直至图中所有和v有路径相通的顶点都被访问到。若图中尚有顶点未被访问到,则另选图中一个曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

伪代码

DFS(G)
//实现给定图的深度优先查找遍历
//输入:图G = <V,E>
//输出:图G的顶点,按照被DFS遍历第一次访问到的先后次序,用连续的整数标记
将V中的每个顶点标记为0,表示还“未访问”
count<——0
for 每个顶点 v in V do
if v 被标记为0
    dfs(v)
    
dfs(v)
//递归访问所有和v相连接的未访问顶点,然后按照全局变量count的值
//根据遇到它们的先后顺序,给它们附上相应的数字
count<—— count + 1;用count标记v
for 每个顶点 w in V 邻接 to v do
if w 被标记为0
dfs(w) 

模板:

void dfs()//参数用来表示状态  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记)//是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
 
    }  
}

举个例子:

迷宫

贴上我的垃圾代码:

#include<bits/stdc++.h> 
using namespace std;
int a[6][6]={0},ans=0;

void dfs(int x,int y,int fx,int fy) {
	
	if(x == fx && y == fy) {
		ans++;
		return;
	}
	else {
	if(a[x][y] == 1)
	a[x][y] = 0;
	
	if(a[x+1][y] == 1)
	dfs(x + 1,y,fx,fy),a[x+1][y]=1; 
	if(a[x-1][y] == 1)
	dfs(x - 1,y,fx,fy),a[x-1][y]=1;
	if(a[x][y+1] == 1)
	dfs(x,y + 1,fx,fy),a[x][y+1]=1;
	if(a[x][y-1] == 1)
	dfs(x,y - 1,fx,fy),a[x][y-1]=1;
}
}

int main() {
	int n,m,t,sx,sy,fx,fy,e,f;
	cin>>n>>m>>t;
	cin>>sx>>sy>>fx>>fy;
	
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	a[i][j]=1;
	 
	for(int i=0;i<t;i++) {
		cin>>e>>f;
		a[e][f] = 0;
	}
	dfs(sx,sy,fx,fy);
	cout<<ans;
	return 0;
}


再看看题解大佬的代码做参考:

#include<iostream>//个人建议不使用万能头文件,如果要使用万能头文件,就不能定义数组map;
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
int map[6][6];//地图;
bool temp[6][6];//走过的标记;
int dx[4]={0,0,1,-1};//打表;
int dy[4]={-1,1,0,0};//打表;
int total,fx,fy,sx,sy,T,n,m,l,r;//total计数器,fx,fy是终点坐标,sx,sy是起点坐标,T是障碍总数,n,m是地图的长和宽,l,r是障碍的横坐标和纵坐标;
void walk(int x,int y)//定义walk;
{
    if(x==fx&&y==fy)//fx表示结束x坐标,fy表示结束y坐标;
    {
        total++;//总数增加;
        return;//返回,继续搜索;
    }
    else
    {
        for(int i=0;i<=3;i++)//0——3是左,右,下,上四个方向;
        {
            if(temp[x+dx[i]][y+dy[i]]==0&&map[x+dx[i]][y+dy[i]]==1)//判断没有走过和没有障碍;
            {
                temp[x][y]=1;//走过的地方打上标记;
                walk(x+dx[i],y+dy[i]);
                temp[x][y]=0;//还原状态;
            }    
        } 
    }
}
int main()
{
    cin>>n>>m>>T;//n,m长度宽度,T障碍个数 
    for(int ix=1;ix<=n;ix++)
        for(int iy=1;iy<=m;iy++)
            map[ix][iy]=1;//把地图刷成1;
    cin>>sx>>sy;//起始x,y 
    cin>>fx>>fy;//结束x,y 
    for(int u=1;u<=T;u++)
    {
        cin>>l>>r;//l,r是障碍坐标;
        map[l][r]=0;
    }
    walk(sx,sy);
    cout<<total;//输出总数;
    return 0;
} 

二,广度优先搜索:
它按照一种同心圆的方式,首先访问所有和初始顶点邻接的顶点,然后是离它两条边的所有未访问顶点,以此类推,直到所有与初始顶点同在一个连通分量中的顶点都访问过了为止。
使用队列来跟踪广度优先搜索的操作是比较方便的,该队列先从遍历的初始顶点开始,将该顶点标记为已访问,再把它们入队。然后,将队头顶点从队列中移去。
伪代码:

BFS(G)
//实现给定图的广度优先查找遍历
//输入:图G = <V,E>
//输出:图G的顶点,按照被BFS遍历访问到的先后次序,用连续的整数标记
将V中的每个顶点标记为0,表示还“未访问”
count<——0
for 每个顶点 v in V do
if v 被标记为0
    bfs(v)
 
 bfs(v)
 //递归访问所有和v相连接的未访问顶点,然后按照全局变量count的值
//根据遇到它们的先后顺序,给它们附上相应的数字
count<——count + 1;用count标记v并且用v初始化队列
while 队列不为空 do
     for 每个邻接前顶点的顶点 w in V do
       if w 被标记为0
       count<—— count +1;用count标记w
       把w放入队列
       移出队列中的前顶点

对比图的DFS和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;
}

int main()
{
......
 return 0;
}

参考书籍:大话数据结构,算法设计与分析基础。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值