当青训营遇上码上掘金,这个活动其实很早就开始了,由于在上课(还有我总是拖延😂),到现在才开始写,那就开始吧。我们看主题三——寻友之旅。
题目如下:
-
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
解题思路:
小青每一步有三种走法——1、向后走一步(公交不能后退);2、向前走一步;3、坐公交
所以,可以使用广度优先,走过后做一个标记,然后往后走继续寻找,直到走到小码家为止。思路:
- 后退n-k步(如果n>k)
- 从当前节点出发,广度优先搜索,每个节点可以扩展3个位置,判断该位置是否为小码家的位置,如果是返回扩展走过的距离;否则,判断位置是否越界且未访问,如果是则距离加1后,将位置入队(其他情况)
举个例子,当n=5,k=17时,借鉴网上一个博主的图
从5这个点出发,一分钟可以到4,6,10,这三个位置。广度优先,从4这个点出发,一分钟可以到3,5,8,这三个位置,其中5重复;从6这个点出发可以到5,7,12,这三个位置,其中5重复,从10这个位置可以到9,11,20,这三个位置。广度优先,从3这个点出发可以到2,4,6,4,6重复;从8出发,到7,9,16,其中,7,9重复;从7出发,到6,8,14,其中6,8重复,从12出发,到11,13,24,其中11重复;从9出发,到8,10,18,其中8,10重复;从11出发,到10,12,22,其中10,12重复;从20出发,到19,21,40。
代码
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
void bfs(int n, int k) {
int step[3]; //每次都有三种选择,用来记录位置
int visit[100001]; //记录最小时间
queue<int> q;
memset(step, 0, sizeof(step));
memset(visit, -1, sizeof(visit));
q.push(n); //入队
visit[n] = 0; //出发时为0分钟
while (!q.empty()) {
int current = q.front(); //取队首数据
q.pop(); //pop出队
if (current == k) { //到小码家了
break;
}
step[0] = current * 2;
step[1] = current + 1;
step[2] = current - 1;
for (int i = 0; i < 3; i++) { //广搜入队
if (step[i] >= 0 && step[i] < 100001 && visit[step[i]] == -1) {
q.push(step[i]);
visit[step[i]] = visit[current] + 1; //记录时间
}
}
}
cout <<"小青到小码家所需的最短时间为:"<< visit[k] << "分钟。" << endl;
}
int main()
{
int n, k;
cout<<"请输入N和K(以空格隔开):"
cin>>n>> k;
bfs(n, k);
return 0;
}