当青训营遇上码上掘金
题目
题目内容:小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。 步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1 公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
题解
根据题目要求,我们可以先对小青的地点N进行分类:
-
小青的地点N大于小码的地点K,即
N > K。那么由于小青在乘坐公交时不能向后出发,所以小青不能选择坐公交的方式了,只剩下通过
x - 1步行到小码家。此时答案显然为N到K的直线距离,即:N - K。 -
小青的地点N小于小码的地点K,即
N < K。小青此时可以选择两种方式到达小青家,但是由于
2 × X的方式显然更快,我们利用贪心法可以快速得到,小青首先应该选择乘坐公交。但是由于公交前进距离的特殊性,每次× 2,可以得到,在第i次乘坐公交后,其位置在 2 × Xi 处,此时,如果小青的位置如果已经大于或等于K,此时小青只能步行往回走,这显然可能会浪费一部分步数,除此之外,我们还可以选择在上一次公交后直接步行到小码家。那么我们可以比较此次之后小青到小码家需要的步数和小青i-1次后步行到小码家的距离,得到较小值即为答案。 -
小青的地点N等于小码的地点K,即
N = K。显然,此时答案为0。
综上所述,我们可以写下以下代码:
(如果我们的go程序需要读取终端内容,那么我们可以使用fmt包的Scanln或者Scanf方法。两个方法会返回一个scan变量和err错误,我们除了查看是否报错外,需要注意传入的读取终端的变量须要使用指针,保证终端的内容可以顺利回传到变量上去。)
func main() {
var N, K int
_, err := fmt.Scanf("%d %d", &N, &K)
if err != nil {
return
}
// 将N > K和N = K 合并为一种情况
switch N < K {
case true:
ans := 0
for N < K {
N *= 2
ans++
}
// 比较i次后小青到小码家需要的步数和小青i-1次后步行到小码家的距离
if ans+(N-K) < ans-1+(K-N/2) {
fmt.Println(ans + (N - K))
} else {
fmt.Println(ans - 1 + (K - N/2))
}
case false:
fmt.Println(N - K)
}
}
项目执行如下: