[我和广搜干上了]关于广度优先搜索的种种

前言

不是为什么广搜这么难?

广度优先搜索

好不容易逃出深搜的魔爪,又进广搜的虎穴。(爆炸了)

那么广搜是何方神圣?

广度优先搜索,简称广搜,俗称宽搜,英文是Breadth First Search,简称BFS。

OK,你已经知道了来将姓名,就让我们再深入了解一下Ta,知己知彼百战不殆。

提起广搜,就得先讲一下结构体

内心戏:其实结构体真没什么可讲的

结构体又一个特有趣但特容易错的特点:

定义完要加一个分号

结构体还有一个很省心的特点:

不需要头文件。

结构体还有个说好不好说坏不坏的特点:

可以定义多个其它类型(如int,double 等)的变量。

哦对了,结构体还有一个特点:

得在主函数外定义,注意在using namespace std下面(所有类型都是这样!!!)。

结构体的单词是:

struct。

结构体的定义: 

struct node
{
	int o;
	int step;	
};

在主函数里(广搜可以不定义函数,想定义也没有问题)可以把结构体名字当类型使用,如下:

node h=s.front();

那么这个定义的结构体类型变量就可以使用了,Ta所有的参数和上面定义的结构体是一样的,

可以这么用(下列代码只是举个例子):

h.step=r+v;
if(h.y>98)
{
    cout<<"BAD"<<endl;
    exit(0);
}

OK,广搜的一个知识点的底细已经被你摸透了!

大家都知道递归要用栈,那么我可以很负责任地告诉大家:

广搜要用队列!

我们可以看一下广搜的“工作原理”:

(拿手写笔写的,不太好看请见谅) 

其实广搜的过程就是一个不断入队的过程,队头在变化,使用完就弹出,直到达成目标为止。

这不正好用到队列吗?

OK!广搜的基本信息你已经了解的比较清楚了!

我们就来看看学广搜的第一道题:

输入一个7*5的二维数组,再把Ta一个数一个数地输出,并输出行,列和层数(大家看图理解)。

第一段代码:(不用大家自己写出来,理解透彻就好)

#include<iostream>
#include<queue>  //队列头文件 
using namespace std;
struct node  //定义结构体 
{
	int x,y,step;
};   //记得加分号! 
queue<node> q;  //定义一个队列 
int a[10][8],f[10][8];
int main()
{
	int i,j,k,sum=0;
	//输入数组 
	for(i=1;i<=7;i++)
	{
		for(j=1;j<=5;j++) cin>>a[i][j];
	}
	q.push({1,1,1});  	//第一个数单独处理 
	while(q.size())   //判断条件是队列不为空   !q.empty()也可以 
	{
		node h=q.front();   //定义一个结构体变量用来存储当前队头 
		q.pop();   //弹出队头 
		sum++;   //计数 
		f[h.x][h.y]=1;
		cout<<"行是"<<h.x<<",列是"<<h.y<<",层数是"<<h.step<<",数字为: "<<a[h.x][h.y]<<endl;//按要求输出 
		if(sum==35) return 0;   //判断是否遍历完
		//四个方向 
		//上 
		int tx=h.x-1;  //X坐标减1 
		int ty=h.y;   //Y坐标不变 
		int tstep=h.step+1;   //层数加1 
		if(tx>=1&&ty>=1&&tx<=7&&ty<=5&&f[tx][ty]==0)   //判断越界以及标记 
		{
			q.push({tx,ty,tstep});    //存入 
			f[tx][ty]=1;   //标记 
		}
		//下 
		tx=h.x+1;  //X坐标加1 
		ty=h.y;    //Y坐标不变 
		if(tx>=1&&ty>=1&&tx<=7&&ty<=5&&f[tx][ty]==0)
		{
			q.push({tx,ty,tstep});
			f[tx][ty]=1;
		}
		//左 
		tx=h.x;   //X坐标不变 
		ty=h.y-1;   //Y坐标减1 
		if(tx>=1&&ty>=1&&tx<=7&&ty<=5&&f[tx][ty]==0)
		{
			q.push({tx,ty,tstep});
			f[tx][ty]=1;
		}
		//右 
		tx=h.x;   //X坐标不变 
		ty=h.y+1;    //Y坐标加1 
		if(tx>=1&&ty>=1&&tx<=7&&ty<=5&&f[tx][ty]==0)
		{
			q.push({tx,ty,tstep});
			f[tx][ty]=1;
		}
	}
	return 0;
}

大家看晕了吗?

我刚学的时候是真晕了..................... 

不过希望大家先多看看理解透彻。

理解透彻了吗?

OK,升级版来了!

#include<iostream>
#include<queue>
using namespace std;
struct node
{
	int x,y;
};
queue<node> s;
int r,c,a[105][105],f[105][105],i;
//定义两个数组:XY坐标的偏移量 ,方便变化 
int dx[5]={0,0,0,-1,1};
int dy[5]={0,-1,1,0,0};
void bfs()
{
	s.push({1,1});
	f[1][1]=1;
	while(s.size())
	{
		node h=s.front();
		s.pop();
		cout<<a[h.x][h.y]<<endl;
		//四个方向 
		for(i=1;i<=4;i++)
		{
			//变化 ,加减偏移量 
			int a=h.x+dx[i];  
			int b=h.y+dy[i];
			if(a>=1&&a<=r&&b>=1&&b<=c&&f[a][b]==0)
			{
				s.push({a,b});
				f[a][b]=1;
			}
		} 
	}
}
int main()
{
	int i,j;
	cin>>r>>c;
	for(i=1;i<=r;i++)
	{
		for(j=1;j<=c;j++)
		{
			cin>>a[i][j];
		}
	}
	bfs();
} 

用了两个数组记录了偏移量,再使用循环,方便多了!

既然大家基本代码理解透了,那么我们就开始

做题

哦对了,给你说个好消息,上面那段简洁版代码就是

OpenJudge - 21:二维数组右上左下遍历

这道题的AC代码!!!

接下来还有两道题目:

一,

OpenJudge - 2971:抓住那头牛

解析: 

#include<iostream>
#include<queue>   //队列头文件 
using namespace std;
struct node  //定义结构体 
{
	int x;
	int step;
};   //分号! 
queue<node> s;   //定义队列 
int k,n,f[100005],i,j,a[5]={0,-1,1},tc,tx;//f数组是标记,a数组是偏移量 
void bfs()
{
	if(n==k)  //如果农夫和牛开始就在同一位置上,农夫就不用跑了 ,需要判断 
	{
		cout<<"0";   //一次也不用跑 
		return;
	}
	//第一个单独处理 
	s.push({n,0});   
	f[n]=1;
	while(s.size())   //条件:数组不为空 
	{
		node h=s.front();   //定义结构体变量并记录队头 
		s.pop();    //弹出 
		for(int i=1;i<=2;i++)   //循环 
		{
			tx=h.x+a[i];   //X坐标与偏移量的加减 
			tc=h.step+1;   //步数(就是层数)的记录 
			if(tx>=0&&tx<=100000&&f[tx]==0)   //越界以及标记的判断 
			{
				if(tx==k)    //如果抓住了就输出并结束 
				{
					cout<<tc;
					return;
				}
				s.push({tx,tc});   //存入 
				f[tx]=1;    //标记 
			}
		}
		tx=h.x*2;   //乘2的移动操作无法用偏移量表示,单独处理 
		if(tx>=0&&tx<=100000&&f[tx]==0)
		{
			if(tx==k)
			{
				cout<<tc;
				return;
			}
			s.push({tx,tc});
			f[tx]=1;
		}
		tc=h.step+1;
	}
}
int main()
{
	cin>>n>>k;   //输入 
	bfs();    //调用 
	return 0;
}

AC代码:

#include<iostream>
#include<queue>
using namespace std;
struct node
{
	int x;
	int step;
};
queue<node> s;
int k,n,f[100005],i,j,a[5]={0,-1,1},tc,tx;
void bfs()
{
	if(n==k)
	{
		cout<<"0";
		return;
	}
	s.push({n,0});
	f[n]=1;
	while(s.size())
	{
		node h=s.front();
		s.pop();
		for(int i=1;i<=2;i++)
		{
			tx=h.x+a[i];
			tc=h.step+1;
			if(tx>=0&&tx<=100000&&f[tx]==0)
			{
				if(tx==k)
				{
					cout<<tc;
					return;
				}
				s.push({tx,tc});
				f[tx]=1;
			}
		}
		tx=h.x*2;
		if(tx>=0&&tx<=100000&&f[tx]==0)
		{
			if(tx==k)
			{
				cout<<tc;
				return;
			}
			s.push({tx,tc});
			f[tx]=1;
		}
		tc=h.step+1;
	}
}
int main()
{
	cin>>n>>k;
	bfs();
	return 0;
}

二,斗地主大师

把上面那道抓牛问题学懂做这道题就比较轻松了。

搜索"斗地主大师" 第1页 | 考级竞赛题库

注:因“斗地主大师”一题数字太大,于是本菜鸡给自己降低了一些难度,把数字最大的限制从2^31调小成了一千万 。

代码:

#include<iostream>
#include<queue>
using namespace std;
struct node
{
	int o;
	int step;	
};
queue<node> s;
int p,q,x,y,f[10000005],tx,tstep;
void fun()
{
	s.push({p,0});
	f[p]=1;
	if(p==q) 
	{
		cout<<0;
		return ;
	}
	while(s.size())
	{
		node h=s.front();
		s.pop();
		if(h.step>52)
		{
			cout<<"Failed";
			return;
		}
		tx=h.o-x;		
		tstep=h.step+1;
		if(tx<=10000000&&tx>=0&&f[tx]==0)
		{
			if(tx==q)
			{
				cout<<tstep;
				return;
			}
			s.push({tx,tstep});
			f[tx]=1;
		}
		tx=h.o*y;
		tstep=h.step+1;
		if(tx<=10000000&&tx>=0&&f[tx]==0)
		{
			if(tx==q)
			{
				cout<<tstep;
				return;
			}
			s.push({tx,tstep});
			f[tx]=1;
		}

	}
}
int main()
{
	cin>>p>>q>>x>>y;
	fun();
}

其实广搜如果多看看,多理解理解,你就会发现:广搜其实并不是很难,但是很好用

不知不觉已经写了这么多了 ,希望对你有帮助!

结束!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值