1100 抓住那头牛(bfs)

1. 问题描述:

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点 N,牛位于点 K。
农夫有两种移动方式:
从 X 移动到 X−1 或 X+1,每次移动花费一分钟
从 X 移动到 2∗X,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

输入格式

共一行,包含两个整数N和K。

输出格式

输出一个整数,表示抓到牛所花费的最少时间。

数据范围

0 ≤ N,K ≤ 10 ^ 5

输入样例:

5 17

输出样例:

4
来源:https://www.acwing.com/problem/content/description/1102/

2. 思路分析:

分析题目可以知道我们需要求解从起点N到终点K的最短路径,而且从一个状态到另外一个状态花费的步数为1,所以所有边权都是1,也即可以使用宽搜来解决,这道题目涉及到三个操作,加1,减1和乘2操作,因为宽搜的时间复杂度为O(n),所以需要计算一下可以搜索的范围使得搜索是有意义的,这样可以降低时间复杂度,避免不必要的搜索。首先确定可以移动位置的最小值,可以发现最小值肯定是0,因为如果我们走到了负数的位置而K是大于0的所以只能够通过+1操作再走回来,所以属于来回走了步数反而多了没有什么意义,还不如不走,所以不可能走到负数的位置,那么最小值应该大于等于0,当N在K的右侧那么只能够通过-1的操作走过来,那么最大值小于等于10 ^ 5,当N在K的左侧,可以通过加1和乘2的操作到达K,如果通过乘2的操作使得到达的位置大于了10 ^ 5,那么可以先通过减1再乘2的操作到达K所以最大值也小于等于10 ^ 5,所以我们在操作的时候范围为:[0,10 ^ 5],实际在做的时候可以开大一点的数组,因为需要记录最短距离所以可以使用一个dis数组,dis数组不仅可以记录最短距离而且还可以充当bfs的判重数组,因为第一次搜到的一定是最短的。

3. 代码如下:

import collections


class Solution:
    def bfs(self, n: int, k: int):
        # 数组中最大的位置为N, 最小为0
        N = 10 ** 5 + 10
        q = collections.deque([n])
        dis = [-1] * N
        dis[n] = 0
        while q:
            p = q.popleft()
            # 因为题目一定有解所以当发现到达目标位置的时候直接返回最短距离
            if p == k: return dis[p]
            if p - 1 >= 0 and dis[p - 1] == -1:
                q.append(p - 1)
                dis[p - 1] = dis[p] + 1
            if p + 1 < N and dis[p + 1] == -1:
                q.append(p + 1)
                dis[p + 1] = dis[p] + 1
            if p * 2 < N and dis[p * 2] == -1:
                q.append(p * 2)
                dis[p * 2] = dis[p] + 1

    def process(self):
        n, k = map(int, input().split())
        return self.bfs(n, k)


if __name__ == '__main__':
    print(Solution().process())

猜你喜欢

转载自blog.csdn.net/qq_39445165/article/details/121642031