题目来源
POJ - 3278
题目内容
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
知识点
搜索:广(宽)度搜索BFS
题目思路
The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.
农夫约翰最快到达逃跑的奶牛的方法是沿着以下路径移动:5-10-9-18-17,这需要4分钟。
使用广度优先搜索(BFS)来解决这个问题。
假设起点是N,终点是K,我们可以从起点开始,每次移动都有三种可能性:
- 步行到X-1点;
- 步行到X+1点;
- 传送到2×X点。
我们可以将每个点看作一个节点,根据这三种移动方式构建一个图。然后使用BFS遍历图,直到找到终点K为止。在遍历的过程中,我们可以记录每个点所经过的步数,以便后续计算总共需要的时间。
具体步骤如下:
- 定义一个队列来存储待遍历的节点,初始化时将起点N加入队列;
- 定义一个数组dist,用来记录每个点的步数,初始化时将所有点的步数设置为一个较大的值,表示未访问过;
- 设置起点N的步数为0,表示已经访问过;
- 使用while循环来遍历队列中的节点,直到队列为空为止;
- 在循环内部,取出队列的第一个节点,判断是否为终点K,如果是,则返回该节点的步数,表示找到了终点;
- 否则,对当前节点进行三种移动操作,判断移动后的点是否已经访问过(即dist数组中的值是否为一个较大的值),如果没有访问过,则将该点加入队列,并将其步数设置为当前节点的步数加1;
- 重复步骤4-6,直到找到终点K为止。
最后,返回终点K在dist数组中的步数,即为所需的时间。我们可以使用广度优先搜索(BFS)来解决这个问题。假设起点是N,终点是K,我们可以从起点开始,每次移动都有三种可能性:
- 步行到X-1点;
- 步行到X+1点;
- 传送到2×X点。
我们可以将每个点看作一个节点,根据这三种移动方式构建一个图。然后使用BFS遍历图,直到找到终点K为止。在遍历的过程中,我们可以记录每个点所经过的步数,以便后续计算总共需要的时间。
具体步骤如下:
- 定义一个队列来存储待遍历的节点,初始化时将起点N加入队列;
- 定义一个数组dist,用来记录每个点的步数,初始化时将所有点的步数设置为一个较大的值,表示未访问过;
- 设置起点N的步数为0,表示已经访问过;
- 使用while循环来遍历队列中的节点,直到队列为空为止;
- 在循环内部,取出队列的第一个节点,判断是否为终点K,如果是,则返回该节点的步数,表示找到了终点;
- 否则,对当前节点进行三种移动操作,判断移动后的点是否已经访问过(即dist数组中的值是否为一个较大的值),如果没有访问过,则将该点加入队列,并将其步数设置为当前节点的步数加1;
- 重复步骤4-6,直到找到终点K为止。
最后,返回终点K在dist数组中的步数,即为所需的时间。
AC代码
#include "iostream" // 引入输入输出流库
#include "queue" // 引入队列库
using namespace std; // 使用标准命名空间
int a, b; // 定义两个全局变量a和b
const int MAXN = 1e5 + 5; // 定义一个常量,表示数组的最大长度
int f[MAXN]; // 定义一个数组,用于存储到达每个数字的最小步数
queue<int> q; // 定义一个队列,用于BFS的遍历
// BFS函数,用于找到从a到b的最小步数
void bfs() {
q.push(a); // 将起始数字a放入队列
while (q.size()) { // 当队列不为空时进行循环
int t = q.front(); // 获取队列前端的数字
q.pop(); // 将队列前端的数字弹出
if (t == b ) { // 如果这个数字是目标数字b
printf("%d", f[t]); // 输出到达b的最小步数
return ; // 函数结束
}
// 以下是尝试三种不同的操作,并更新对应的步数
if (t - 1 >= 0 && !f[t - 1]) f[t - 1 ] = f[t] + 1, q.push(t - 1); // 数字减1
if (t + 1 <= b && !f[t + 1]) f[t + 1 ] = f[t] + 1, q.push(t + 1); // 数字加1
if (t << 1 <= b && !f[t << 1]) f[t << 1 ] = f[t] + 1, q.push(t << 1); // 数字乘2
}
return ; // 函数结束
}
int main () {
scanf("%d%d",&a,&b); // 输入起始数字和目标数字
bfs(); // 调用BFS函数
return 0; // 程序结束
}