当青训营遇上码上掘金
题目:主题三之寻友之路
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式 可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
问题:请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
解题思路
已知小青行动的方式有两种,求通勤的最短时间,可以看作是寻找最短路径问题,一般可以考虑遍历的算法(如深/广度优先搜索),在这道题中,我们可以考虑使用动态规划的方法求最优解,动态规划和其它遍历算法都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划保存子问题的解,避免重复计算。解决动态规划问题的关键是找到状态转移方程,这样我们可以通过计算和储存子问题的解来求解最终问题。
在这道题目中,小青和小码的家在一条直线上,可以用一维的动态数组求解,我们定义一个数组dp,dp[i]表示从小青家也就是N点到小码家K点通勤的最小时间,小青出行有两种方式,步行,一分钟往前后移动一格,公交,一分钟移动两倍所在位置值的距离且不能后退,那么对于某一点 i:
- 首先如果他在小青家N点前面,公交不能后退,只能步行,那么最短时间就是N - i
- 如果在小青家N点后面,则可以坐公交:
- 如果是偶数位置,那么它可以直接由前面的点坐公交到达时间最短,状态转移为dp[i] = dp[i/2] + 1;
- 如果是奇数位置,那么它前后两格距离是偶数位置,状态转移为dp[i] = Min(dp[i-1] + 1, dp[(i+1)/2] + 2)。
从0开始遍历到K点停止,输出到达K点的最优解。
具体见下面代码实现。
代码实现(golang)
import "fmt"
func Min(x, y int) int {
if x < y {
return x
}
return y
}
func main() {
var N int
var K int
fmt.Println("请输入K和N,用空格隔开,0 ≤ N, K ≤ 100000")
fmt.Scanf("%d %d", &N, &K)
dp := make([]int,K+1)
for i := 0 ; i<K+1 ; i++{
if i<=N{
dp[i]=N-i
}else{
if i%2 == 0{
dp[i] = dp[i/2]+1
}else{
dp[i] = Min(dp[(i+1)/2]+2, dp[i-1]+1)
}
}
}
fmt.Println("最短时间为:", dp[K])
}
go语言有Math包可以比较浮点数的大小,但不支持整数大小的比较,当然编写一个比较大小的函数很简单。
代码链接:https://code.juejin.cn/pen/7189588376809373754
最后测试结果如下: