目录
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相关用法可以看这位博主的博文:
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]用来储存正向路径 (同样反向储存),而后将这个数组反向遍历输出坐标即可。