【算法每日一练]-bfs 篇5 奇怪的电梯 ,马的遍历 ,流星坠落

 看一下今天的内容

目录

bfs简述:

   上代码:

题目: 奇怪的电梯

   思路: 

题目: 马的遍历

   思路 :

题目 :流星坠落 

   思路:


bfs简述:

广度优先算法(Breadth-First-Search),简称BFS。从知识点看属于图结构的搜索算法,是一种相对容易理解的简单算法。
        BFS算法从问题的初始状态(起点)出发,根据状态转换规则(图结构中的边),遍历所有可能的状态(其他节点),直到找到终结状态(终点)。因此BFS算法的复杂度和状态集合的总数密切相关。
        BFS算法虽然出自图结构,但其常用的领域却不是解决图论相关问题。一些常见的问题形式如(1)走迷宫最短路径(2)数字按规则转换的最少次数(3)棋盘上某个棋子N步后能到达的位置总数(4)病毒扩散计算(5)图像中连通块的计算。小结:BFS算法常用于求最短的步数或者求扩散性质的区域问题。

 

  

上代码:

//bfs(广搜模板)       
q.push(初始状态);
while(!q.empty()){
	tmp =q.front(); q.pop();
	for(枚举所有情况v){
		if(情况合法并去重){
			标记操作; q.push(v);
		}
	}
}

  
好了,学会了这种思想后就直接上题了。

  

题目:奇怪的电梯

  

思路: 

抓关键词:至少按几次,相当于至少走多少步,bfs错不了。

从最开始状态不断让后继入队即可,直到整个队空为止。

  

#include<bits/stdc++.h> //(广度优先)(有点像图的基本遍历)
using namespace std;
int n,a,b,to[205];
bool vis[205];    //标记哪个楼层到过,防止再到一次(用于枝剪)
struct node{
	int id,step; //id表示楼层号,step表示按钮次数
	}x;
int main()
{
	scanf("%d%d%d",&n,&a,&b);
	for(int i=1;i<=n;i++) scanf("%d",&to[i]);
	queue<node> q;
	q.push((node){a,0});
	while(q.size())
	{
		x=q.front();q.pop(); //保存
		if(x.id==b) break;
		if(x.id+to[x.id]<=n&&!vis[x.id+to[x.id]])   //防越界,枝剪:来过就不用来了
		{
			q.push((node){x.id+to[x.id],x.step+1}); //标记,入队
			vis[x.id+to[x.id]]=1;   //标记来过
		}
		if(x.id-to[x.id]>=1&&!vis[x.id-to[x.id]])//写的丑了点,不会入队两次的放心吧,有判重呢
		{
			q.push((node){x.id-to[x.id],x.step+1});
			vis[x.id-to[x.id]]=1;
		}
	}
	if(x.id==b) printf("%d",x.step);
	else printf("-1");  //bfs只要不是break出来的的,一定根本就到不了
	return 0;
}

再来一题吧

  

题目:马的遍历

  

思路 :

理解马的走路方式,然后设置转移数组即可。

然后f[i][j]表示到这个点所需要的步数。不断维护这个数组即可

  

#include <bits/stdc++.h>   //马的遍历   (广度优先bfs)
using namespace std;
struct point{ //坐标
	int x,y;
};
int main(){
	int n,m,x0,y0,f[404][404],dx[8]={-1,-2,-2,-1,1,2,2,1},dy[8]={-2,-1,1,2,2,1,-1,-2};  //动态转移数组
	queue<point> q;
	memset(f,-1,sizeof(f));
	cin>>n>>m>>x0>>y0;
	f[x0][y0]=0;
	point tp={x0,y0},p; //tp是起始点,p是下一步的随机点
	q.push(tp);//队列起始状态
	while(!q.empty()){
		tp=q.front(); q.pop(); //暂存,弹出
		for(int i=0;i<8;i++){
			int x=dx[i]+tp.x,y=dy[i]+tp.y; //(x,y)是下一步的坐标
			if(x<1||x>n||y<1||y>m||f[x][y]!=-1) continue;
			f[x][y]=f[tp.x][tp.y]+1; //标记
			p={x,y}; q.push(p);     //入队
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cout<<f[i][j]<<"    ";
		}
		cout<<'\n';
	}
	return 0;
}

  

最后一题

题目:流星坠落 

  

 

  

 思路:

如果当流星按时间顺序一秒一秒的落下很不现实,时间复杂度太大了。还不如先打表,再搜索呢

其实完全可以让流星全部降落,只需要记录下每个点烧焦的最早时间,未设置则表示这个点永远不会被烧到。然后让我们的主角开始bfs跑图,走那些目前还安全的地方,如果能走到永远安全的地方就直接结束bfs即可。否则,当我们bfs全部跑完的时候即表示根本找不到这样的位置!

   

#include <bits/stdc++.h>//P2895 (bfs广度优先)
using namespace std;
struct point{
	int x,y,t,step,vis;//(x,y)是坐标,t是流星的坠落时间,step是贝茜当前步数也是当前时间数
}ps[1005][1005];
int main(){
	int m,x,y,t,tx,ty,dx[5]={-1,1,0,0},dy[5]={0,0,-1,1};//转移数组
	cin>>m;
	memset(ps,-1,sizeof(ps));
	for(int i=0;i<1000;i++)        //ps结构体的x,y初始化
		for(int j=0;j<1000;j++){
			ps[i][j].x=i;	ps[i][j].y=j;
		}
	for(int i=0;i<m;i++){       //ps结构体的t初始化(表示t时间后烧毁)
		cin>>x>>y>>t;
		for(int j=0;j<5;j++){//周围都要烧焦
			tx=x+dx[j];	ty=y+dy[j];
			if(tx<0||ty<0) continue;  //防止数组越界
			if(ps[tx][ty].t==-1||ps[tx][ty].t>t) ps[tx][ty].t=t;//原位置没有被占或原位置早就被烧毁,时间被更新
		}
	}
	queue<point> q;
	ps[0][0].vis=1; ps[0][0].step=0;//step就是记录时间
	q.push(ps[0][0]);  //队列初始化
	while(!q.empty()){
		point p=q.front(); q.pop();  //暂存,出队
		for(int i=0;i<4;i++){
			tx=p.x+dx[i];	ty=p.y+dy[i];
			if(tx<0||ty<0||ps[tx][ty].vis==1) continue; //防止越界,防止重复访问(因为再回去或再停留原地已经没必要,时间已经变晚了)
			if(ps[tx][ty].t==-1){   //t为-1的位置是永不被烧的位置,就是到了安全位置
				cout<<p.step+1;
				return 0;
			} 
			if(p.step+1<ps[tx][ty].t){//到达烧毁之前位置
			ps[tx][ty].vis=1;//标记
			ps[tx][ty].step=p.step+1;//操作
			q.push(ps[tx][ty]);//入队
	    	}
		}
	}
	cout<<-1;
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值