自用ACM模板之BFS(循环)(待完善)

前言:本人是个实力很弱但立志变强的ACM小白(使用C++)。此篇BFS模板目前只有循环实现,等之后学习了队列实现或递归实现会回头补充。

BFS即广度优先搜索,在搜索一个状态下一步变化之后可能产生的状态时,先遍历出所有可能产生的新状态,然后再逐一从新状态出发搜索再下一步变化可能产生的状态。

可用树状图表达:

第一类:保存整棵搜索树

显然第一类和第二类对空间大小的要求是不一样的,能满足的题意要求也不太一样,根据实际情况选用

用一个有限列无限行的二维数组(命名为bfs)储存所有搜索结果,其中一列储存搜索层数(变化步数),其他列储存搜索结果。

辅助变量:

  • ibfs - 总是表示bfs数组下一个空行的下标,其值每搜得一个结果+1;
  • bfslayerlength - 总是表示当前层已搜索出的状态,其值每搜得一个结果+1,该层搜索完毕后其值即为当前层的结果数(用变量bfslayerlengthtemp维护这个值),清零之后再搜索下一层;
  • isanswerfound - 用于辅助搜索到最终所需状态时跳出bfs搜索循环、判定不可能情况等;
  • iibfs - 存储上一层搜索完之后ibfs的值,表示当前层的起点下标。
  • bfslayerlengthtemp - 上面已经提过,用来存储搜索完一层后bfslayerlength的值,因此此值表示上一层的搜索结果数;

以上最后两个变量相结合就可以表示出上一层搜索结果的下标范围,声明它们的目的也在于此(上一层的搜索结果即搜索当前层的出发点)。以下把它们称作维护变量:

搜索过程示例:

刚刚搜索完第3层时:

 bfs[][0]bfs[][1]...  
bfs[0][]1状态1  
bfs[1][]2状态2<- iibfs - bfslayerlengthtemp 
bfs[2][]2状态3  
bfs[3][]2状态4  
bfs[4][]3状态5<- iibfs<- ibfs - bfslayerlength
bfs[5][]3状态6  
bfs[6][]3状态7  
bfs[7][]3状态8  
bfs[8][]00 <- ibfs
...    

给维护变量iibfs、bfslayerlengthtemp赋值,清零bfslayerlength后,准备搜索第4层:

 bfs[][0]bfs[][1]...  
bfs[0][]1状态1  
bfs[1][]2状态2  
bfs[2][]2状态3  
bfs[3][]2状态4  
bfs[4][]3状态5<- iibfs - bfslayerlengthtemp 
bfs[5][]3状态6  
bfs[6][]3状态7  
bfs[7][]3状态8  
bfs[8][]00<- iibfs

<- ibfs - bfslayerlength

<- ibfs

...    

搜索第4层中:

 bfs[][0]bfs[][1]...  
bfs[0][]1状态1  
bfs[1][]2状态2  
bfs[2][]2状态3  
bfs[3][]2状态4  
bfs[4][]3状态5<- iibfs - bfslayerlengthtemp 
bfs[5][]3状态6  
bfs[6][]3状态7  
bfs[7][]3状态8  
bfs[8][]4状态9<- iibfs<- ibfs - bfslayerlength
bfs[9][]4状态10  
bfs[10][]4状态11  
bfs[11][]00 <- ibfs
...    
代码模板
//定义BFS所需变量
short bfs[10005][2];//不一定够用
int ibfs;
int iibfs;
int bfslayerlength;
int bfslayerlengthtemp;
bool isanswerfound;

//BFS
//初始化
for (int i = 0; i < 10005; i++)
{
	bfs[i][0] = 0;
	bfs[i][1] = 0;
}
bfs[0][0] = 1; bfs[0][1] = 1;//设置要搜索的起始状态
ibfs = 1;
iibfs = 1;
bfslayerlengthtemp = 1;
isanswerfound = false;

//开始搜索,此while循环每执行一次,搜索一层
while (true)
{
	bfslayerlength = 0;
	for (int i = iibfs - bfslayerlengthtemp; i < iibfs; i++)
	{

		//在这里写上搜索规则,被搜数即bfs[i][1]...,新搜索结果存储位置为,bfs[ibfs][1]...,每当发生有一个新搜索结果加入bfs数组时一定还要伴随以下这段代码

		bfs[ibfs][0] = bfs[iibfs - 1][0] + 1;//这里的bfs[iibfs - 1][0]即上一层层数
		if ()//括号中写上出现了所需状态时满足的条件,例如bfs[i][1]...==所需状态
		{

			//这里可再写上搜到所需状态之后,要在跳出循环之前执行什么,例如输出步数或层数

			isanswerfound = true;
			break;
		}
		ibfs++;
		bfslayerlength++;


	}
	if (isanswerfound == true)//这里需再加上其他要停止bfs搜索的条件,例如层数超出规定范围、没有新增任何结果(bfslayerlength == 0)等
		break;

	bfslayerlengthtemp = bfslayerlength;
	iibfs = ibfs;
}
if (isanswerfound == false)
{
	//这里写上不可能搜索到所需状态时要做什么
}

 

第二类:“边搜边扔”,只保存当前层和上一层搜索结果,但在搜索树分枝数量庞大时能节省不少空间

用两个无限一维数组bfs、bfstemp分别储存当前层和上一层搜索结果(或无限行有限列二维数组,储存一种状态需要多少个数据就用多少列),第一行(即下标为0的位置)储存该组搜索结果所在层数,其他行储存搜索结果。

先将起始状态放入bfstemp,搜索bfstemp中的状态,搜索结果放入bfs,然后再将bfs拷贝至bfstemp并清空bfs,再次从bfstemp里的数据出发搜索下一层...以此反复循环。

 bfstempbfs bfstempbfs bfstempbfs
[0]23 34 34
[1]状态2状态4 状态40 状态4状态8
[2]状态3状态5->状态50->状态5状态9
[3]0状态6 状态60 状态6状态10
[4]0状态7 状态70 状态7状态11
[5]00 00 0...

辅助变量:

  • ibfs - 总是表示数组bfs的下一空位下标,作为bfs数组终点依据;
  • ibfstemp - 总是表示数组bfstemp的下一空位下标,作为bfstemp数组终点依据;
  • isanswerfound - 作用同第一类;

与第一类相比,第二类只要这么多辅助变量就够了。

代码模板
short bfstemp[10005];
int ibfs;
int ibfstemp;
bool isanswerfound;

//BFS
//初始化
for (int i = 0; i < 10005; i++)
{
	bfs[i] = 0;
	bfstemp[i] = 0;
}
bfstemp[0] = 1; bfstemp[1] = 1;//设置要搜索的起始状态
ibfs = 1;
ibfstemp = 1;
isanswerfound = false;

//开始搜索,此while循环每执行一次,搜索一层
while (true)
{
	ibfs = 1;
	for (int i = 1; i < ibfstemp; i++)
	{

		//这里写上搜索规则,被搜数为bfstemp[i],新结果存储位置为bfs[ibfs],每发生有新搜索结果写入要伴随以下这段代码

		if ()//括号中写上出现了所需状态时满足的条件,例如bfs[i]==所需状态
		{

			//这里可再写上搜到所需状态之后,要在跳出循环之前执行什么,例如输出步数或层数

			isanswerfound = true;
			break;
		}
		ibfs++;


	}
	if (isanswerfound == true)//这里需再加上其他要停止bfs搜索的条件,例如层数超出规定范围、没有新增任何结果(ibfs == 1)等
		break;

	for (int i = 0; i < ibfs; i++)//将bfs拷贝到bfstemp,清零bfs
	{
		bfstemp[i] = bfs[i];
		bfs[i] = 0;
	}
	bfs[0] = bfstemp[0] + 1;//赋值层数
}
if (isanswerfound == false)
{
	//这里写上不可能搜索到所需状态时要做什么
}

修改日志

将代码模板从“先搜索完整层再逐一检查这一层有无出现所需状态”改为“每搜索出一个新状态立即检查其是否为所需状态”(2019.2.5 15:35提交)

转载于:https://my.oschina.net/u/4035395/blog/3008319

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值