前言
不是为什么广搜这么难?
广度优先搜索
好不容易逃出深搜的魔爪,又进广搜的虎穴。(爆炸了)
那么广搜是何方神圣?
广度优先搜索,简称广搜,俗称宽搜,英文是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();
}
用了两个数组记录了偏移量,再使用循环,方便多了!
既然大家基本代码理解透了,那么我们就开始
做题
哦对了,给你说个好消息,上面那段简洁版代码就是
这道题的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;//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;
}
二,斗地主大师
把上面那道抓牛问题学懂做这道题就比较轻松了。
注:因“斗地主大师”一题数字太大,于是本菜鸡给自己降低了一些难度,把数字最大的限制从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();
}
其实广搜如果多看看,多理解理解,你就会发现:广搜其实并不是很难,但是很好用。
不知不觉已经写了这么多了 ,希望对你有帮助!
结束!