1. 问题描述:
给定一个正整数 n,我们希望你可以通过一系列的操作,将其变为另一个正整数 m。操作共分两种:
将当前的数乘以 2。
将当前的数减去 1。
要求,在变换过程中,数字始终为正。请你计算,所需要的最少操作次数。
输入格式
一行,两个不同的正整数 n 和 m。
输出格式
一个整数,表示所需的最少操作次数。
数据范围
前 6 个测试点满足 1 ≤ n,m ≤ 10。
所有测试点满足 1 ≤ n,m ≤ 10000。
输入样例1:
4 6
输出样例1:
2
输入样例2:
10 1
输出样例2:
9
来源:https://www.acwing.com/problem/content/description/4303/
2. 思路分析:
分析题目可以知道我们需要求解最少操作次数,属于经典的"最小步数"模型,对于"最小步数"模型一般可以使用宽搜来解决,由题目可知当n > m的时候我们只能够通过减1的操作使得最终变为m的操作次数最小,当n = m的时候不需要任何操作,当n < m的时候尽可能使用乘2操作,2 * n < 2 * m当n > m的时候又会转为减1的操作,所以n的范围不会超过2m,这样在声明距离数组dis的时候声明长度比2m大一点即可,在枚举的时候长度最大不超过2m。
3. 代码如下:
import collections
class Solution:
def process(self):
n, m = map(int, input().split())
N, INF = 20010, 10 ** 10
# 宽搜一般使用dis数组来记录从起点到某个点的最短距离, 由于第一次到达的距离一定是最短的所以不用标记哪些点是否被访问, 没有被访问过的点的距离一定是正无穷的
dis = [INF] * N
dis[n] = 0
# 双端队列
q = collections.deque([n])
while q:
p = q.popleft()
if p == m: return dis[p]
x, y = p * 2, p - 1
# 在小于N的情况下距离更小那么更新答案
if x < N and dis[x] > dis[p] + 1:
dis[x] = dis[p] + 1
q.append(x)
if y >= 1 and dis[y] > dis[p] + 1:
dis[y] = dis[p] + 1
q.append(y)
return -1
if __name__ == '__main__':
print(Solution().process())