BFS 总结

原文:https://blog.csdn.net/u013480600/article/details/45066957?utm_source=copy 

 

                                           BFS学习总结


         给你一个n*m的网格迷宫,迷宫中有些格子不能走,其他的格子都能走。然后给你起点与终点,问你从起点走到终点最少需要多少步?


         上面的问题就是一个典型的BFS问题,对于这类问题来说,只要你掌握了这类问题的关键思想,其实他们都是可以用类似的思路来做的。


         你可以把BFS问题想象成:从一个父亲(起点状态)生儿子(后继状态),儿子又生孙子(后继状态)的过程,只要这个家族中出生了一个满意的后代(终点状态),这个家族就不生了。
         但是如果这个家族中有两个完全一样的人出生(他们的辈分不一定相同),那么后出生的人应该停止让他继续产生后代(状态去重),因为他的所有后代肯定与前面那个人的所有后代一模一样且出生时间反而更晚。
         整个后代的繁殖过程是通过队列来实现的。


         一般的BFS问题我是按下面步骤来做的:


         1)设计状态


         对于上面的问题,我把当前人的位置以及人到该位置所花费的最小时间t,即x和y坐标(行与列坐标)与时间t作为一个有效状态。严格来说x和y才算状态属性,而t只能算状态的当前值。而我们要求的是终点状态的最小时间t值。
         对于每个有效状态X,它可以继续延伸出后继状态。比如本题的X状态的后继状态就是当人在X点然后向上下左右4个方向走时所产生的后继状态(假设4个方向的格子都能走)。
         对于相同的状态我们只处理一次,如果某个状态的后继状态是之前我们已经处理过的状态,那么直接抛弃这个后继状态,不入队列(想想为什么)。
        什么样的状态是一个有效的状态?当给你任意一个BFS状态后,你能根据这个状态把当前BFS网格地图(或BFS全局状态)整个还原出来,那么这个状态就是一个有效的状态。(想想是不是)


         2)记录同类状态最优值


         就是要记录当达到任意一个同类状态(对于本题我们把坐标值相同的状态看成是同一类的)时的最优效果。比如本题,令dist[i][j]==t表示当人到达(i, j)这类状态时,所需要的最小时间t。这个最小时间就是我们要的最优效果。


         3)状态剪枝


         每个状态的后继状态一般都有好几个,这样我们只要做几轮出队入队操作,队列中的状态就是变成指数级别了。所以对于那些出现多次的同类状态,我们只保存一个入队列。且如果上面dist[4][5]==2(即花了2步从起点走到(4,5)点),那么当某个后继状态是(4,5,3)时,我们果断抛弃这个状态(想想为什么,其实(4,5,2)我们就可以抛弃)。
         (其实通过下面的题目可以知道,有些状态需要很多元素来表示,直接导致如果用dist数组来判定重复将会定义dist为dist[][][][][][][][][][]这样,所以这时候我们采取的策略是:HASH判重+保存所有已出现的非重复状态)


         4)查找目标状态


         这个就是当我们在生成后继状态的时候看看是否有目标状态出现(比如坐标在终点的状态)。对于本题来说,只要出现了一个目标状态,我们直接退出即可。因为后面出现的目标状态所花的时间肯定更多(想想为什么)。

          5)代码模板

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define EPS 1e-8
#define MOD 1e9+7
#define LL long long
#define ULL unsigned long long     //1844674407370955161
#define INT_INF 0x7f7f7f7f      //2139062143
#define LL_INF 0x7f7f7f7f7f7f7f7f //9187201950435737471
const int dr[]={0, 0, -1, 1, -1, -1, 1, 1};
const int dc[]={-1, 1, 0, 0, -1, 1, -1, 1};
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。
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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BFS(广度优先搜索)是一种图遍历算法,用于解决图上的问题。在Python中,可以使用队列来实现BFS。引用和引用中的代码示例展示了如何使用BFS遍历树节点的层级。 在代码示例中,首先需要根据给定的树结构创建一个队列,并将根节点入队。然后,使用一个循环来迭代处理队列中的节点。在每次循环中,先获取当前队列的长度n,然后创建一个临时列表temp用于存储当前层级的节点值。 接下来,使用一个for循环遍历当前层级的节点数n,依次从队列中弹出节点a,并将其值a.val添加到临时列表temp中。然后,将该节点的左右子节点(如果存在)加入队列中,以便在下一次迭代中处理。 最后,在每一次循环结束后,将临时列表temp添加到结果列表res中,表示当前层级的节点值已经遍历完毕。当队列为空时,表示已经遍历完整个树,可以返回结果列表res作为最终结果。 需要注意的是,由于队列是先进先出的特性,所以在遍历每一层节点时,可以根据需要选择是否需要翻转临时列表temp来保证节点值的顺序。引用中的示例代码展示了如何使用BFS遍历图。 总结起来,使用BFS可以实现对树节点的层级遍历,通过队列来辅助实现节点的入队和出队操作。每一次从队列中取出节点时,将其子节点加入队列以便后续遍历。这样就可以按照层级顺序遍历树的节点,并将节点值保存到结果列表中返回。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [广度优先算法(BFS)-python](https://blog.csdn.net/weixin_44571635/article/details/123891023)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [基于python模拟bfs和dfs代码实例](https://download.csdn.net/download/weixin_38549721/14839350)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值