算法思想学习-BFS基础题

目录

1.抓住那头牛(openjudge)

题目描述

代码

题解分析

2.走迷宫(openjudge)

题目描述

代码

题解分析

3.迷宫问题(openujdge)

题目描述

代码

题解分析


1.抓住那头牛

题目描述

描述

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:

1、从X移动到X-1或X+1,每次移动花费一分钟

2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

输入

两个整数,N和K

输出

一个整数,农夫抓到牛所要花费的最小分钟数

样例输入

5 17

样例输出

4

代码 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,k;
const int N = 1e5+10;
int path[N];//路径
int d[N];//时间 
int bfs(){
	int hh = 0, tt = 0;//队首和队尾
	path[0] = n;//起点x坐标	 
	memset(d,-1,sizeof(d));//-1代表这个点没走过 
	d[n] = 0;//起始点距离为0 
	while(hh<=tt){//队内还有元素,说明这个图还没遍历完 
		int t = path[hh++];//暂存上一个路径点(同时将其弹出队列) 
		int dx[3] = {-1,1,t};
		for(int i = 0;i<3;i++){//遍历这个点可能情况 
			int x = t + dx[i];
			//如果这个点合法且这个点之前没有走过,那么就继续走
			//这个点第一次走过才是最短时间,已经走过就不是最近了 
			if(x >= 0 && x<=100000 && d[x] == -1){
				//更新这个点的时间和路径
				d[x] =  d[t] + 1;
				path[++tt] = x;//入队 
			}
		} 
	}
	return d[k];
}
int main(){
	scanf("%d%d",&n,&k);
	printf("%d",bfs());
	return 0;
}

题解分析

这一题的话,把所花费的时间看作距离来操作,其他都在注释里了

2.走迷宫 

题目描述

描述

一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。
给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平方向或垂直方向走,不能斜着走。

输入

第一行是两个整数,R和C,代表迷宫的长和宽。( 1<= R,C <= 40)
接下来是R行,每行C个字符,代表整个迷宫。
空地格子用'.'表示,有障碍物的格子用'#'表示。
迷宫左上角和右下角都是'.'。

输出

输出从左上角走到右下角至少要经过多少步(即至少要经过多少个空地格子)。计算步数要包括起点和终点。

样例输入

5 5
..###
#....
#.#.#
#.#.#
#.#..

样例输出

9

代码 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N = 45;
int r,c;
char g[N][N];//记录迷宫
int d[N][N];//步数-1
PII p[N*N];//记录路径 

int bfs(){
	int hh = 0, tt = 0;//队首和队尾 
	p[0] = {0,0};//起点行号和列号
	memset(d,-1,sizeof(d));//当d为-1时表示这个点没走过
	d[0][0] = 0;//距离为0
	//x+1 y, x-1 y, x y+1, x y-1
	while(hh<=tt){//队不为空时,代表还没有走玩所有的点 
		int dx[4] = {1,-1,0,0};
		int dy[4] = {0,0,1,-1};
		PII t = p[hh++];//查看当前点并弹出,寻找它的后继点 
		for(int i = 0;i<4;i++){//遍历四个方向 
			int x = dx[i] + t.first;//更新坐标 
			int y = dy[i] + t.second;
			//如果合法且第一次走且需要是空地 
			if(x >= 0 && x < r && y >= 0 && y < c && d[x][y] == -1 && g[x][y] == '.'){
				//更新
				d[x][y] = d[t.first][t.second] + 1;
				p[++tt] = {x,y};//入队这个点 
			}
		} 
	}
	return d[r-1][c-1];
}

int main(){
	scanf("%d%d",&r,&c);
	getchar();
	for(int i = 0;i<r;i++){
		for(int j = 0;j<c;j++){
			scanf("%c",&g[i][j]);
		}
		getchar();
	}
	printf("%d",bfs()+1);
	return 0;
}

题解分析

这题相比上一题需要用二维数组储存迷宫,用pair来记录路径,其实也可以写一个结构体代替pair,它就相当于一个结构体,然后其余请看注释。

pair相关用法可以看这位博主的博文:

https://blog.csdn.net/sevenjoin/article/details/81937695?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165060338916780271912302%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165060338916780271912302&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-81937695.142^v9^control,157^v4^control&utm_term=pair&spm=1018.2226.3001.4187icon-default.png?t=M3K6https://blog.csdn.net/sevenjoin/article/details/81937695?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165060338916780271912302%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165060338916780271912302&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-81937695.142^v9^control,157^v4^control&utm_term=pair&spm=1018.2226.3001.4187

3.迷宫问题 

题目描述

描述

定义一个二维数组:

int maze[5][5] = {

0, 1, 0, 0, 0,

0, 1, 0, 1, 0,

0, 0, 0, 0, 0,

0, 1, 1, 1, 0,

0, 0, 0, 1, 0,

};


它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

输入

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

输出

左上角到右下角的最短路径,格式如样例所示。

样例输入

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

样例输出

(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

代码 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef pair<int,int> PII;
const int N = 10;
int n = 5;
int g[N][N];//迷宫
int d[N][N];//距离
PII p[N*N];//记录路径
PII pre[N][N];//记录这个点的上一个点(所以是反向记录的)
PII preh[N*N];//储存正向路径 (同样反向储存)

void bfs(){
	int hh = 0, tt = 0;//队首和队尾
	p[0] = {0,0};//起点坐标
	memset(d,-1,sizeof(d));//d为-1代表没走过
	d[0][0] = 0;//起点距离为0
	while(hh<=tt){//队不空(还没遍历完整个迷宫) 
		PII t = p[hh++];//记录当前点以便更新下一个点,同时弹出
		//x+1 y, x-1 y, x y-1, x y+1 
		int dx[4] = {1,-1,0,0};
		int dy[4] = {0,0,-1,1};
		for(int i = 0;i<4;i++){//遍历四个方向 
			int x = dx[i] + t.first;
			int y = dy[i] + t.second;
			if(x >= 0 && x < n && y >= 0 && y < n && d[x][y] == -1 && g[x][y] == 0){
				//更新 
				d[x][y] = d[t.first][t.second] + 1;
				p[++tt] = {x,y};//入队这个点 
				pre[x][y] = t;//这个点是从t.first,t.second点走过来的 
			}
		} 
	} 
	int x = n-1, y = n-1;
	int l = 0;
	while(x || y){//非起点 
		preh[l++] = {x,y};
		PII t = pre[x][y];
		x = t.first, y = t.second;
	}//最后一个点,就是起点,没有存进去
	preh[l++] = {0,0};
	for(int i = l-1;i>=0;i--){
		PII t = preh[i]; 
		printf("(%d, %d)\n",t.first,t.second);
	} 
}
 
int main(){
	for(int i = 0;i<n;i++){
		for(int j = 0;j<n;j++){
			scanf("%d",&g[i][j]);
		}
	}
	bfs();
	return 0;
} 

题解分析

这一题比上一题,本质上多的就是需要输出路径,由于我们的路径在走完之后就已经弹出,所以我们采取定义PII pre[N][N]用来记录这个点的上一个点(所以是反向记录的),可我们要正向输出路径,于是又定义了PII preh[N*N]用来储存正向路径 (同样反向储存),而后将这个数组反向遍历输出坐标即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值