寻友之旅|主题创作活动

108 阅读2分钟

当青训营遇见码上掘金

- 主题三:寻友之旅

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久? 输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

分析

这是一个求最短路径问题,可以使用动态规划来做。

首先,当小码的位置K小于小青的位置N时,此时是最简单的情况,小青只能步行到达小码家。

接着,若小码的位置大于小青,利用动态规划的递归思想。

  • 判断当前位置i是否是偶数节点,若是,则利用MinTime[i]=Min(MinTime[i-1]+1, MinTime[i/2]+1)进行判断,前面两个公式分别代表步行和公交两种交通方式。

  • 若是奇数节点,则先判断乘坐公交的两种方式Bustime=Min(MinTime[(i-1)/2]+2, MinTime[(i+1)/2]+2),其中加2是坐公车到达偶数节点的时间(1)加上到当前节点的时间(1)

源代码

package main

import (
	"fmt"
)

// 动态规划方法
// 当小青位置N在小码位置前面时,只能步行
// 反之,需要决策步行还是公交,利用公式MinTime[i]=Min(MinTime[i-1]+1,MinTime[(i+N)/2]+1)
func FindMinTime(N int, K int) int {

	if N >= K {
		return N - K
	} else {
		MinTime := make([]int, K+1)
		MinTime[N] = 0

		for i := N - 1; i >= 0; i-- {
			MinTime[i] = N - i
		}

		for i := N + 1; i <= K; i++ {
			if i%2 == 0 {
				MinTime[i] = min(MinTime[i-1]+1, MinTime[i/2]+1)
			} else {
				//该点是奇数节点,判断前一个及后一个偶数节点的公交时间
				BusTime := min(MinTime[(i-1)/2], MinTime[(i+1)/2]) + 2
				MinTime[i] = min(MinTime[i-1]+1, BusTime)
			}
		}
		return MinTime[K]
	}
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func main() {
	var N, K int
	fmt.Scan(&N, &K)
	fmt.Println(FindMinTime(N, K))
}

实验结果

image.png