主题 3:寻友之旅

697 阅读2分钟

当青训营遇上码上掘金

主题内容

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

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

题解

bfs

首先将小青NN和小码XX的位置看作数轴,0为原点,则分为N>XN>X时所需时间time=NXtime=N-X;N<XN<X时,N下一步可到达的点有N1N-1,N+1N+1,N2N*2,则可以考虑用bfs求解最短距离的思想。每一个可达点可抽象为图中的一个点,每个点之间的距离为1,该题则转化为给定起点和终点,求最短距离。该算法的时间复杂度为O(3N)O(3^N).

代码(golang)


package main

import "fmt"

const N = 200010

func bfs(beg, end int) int {
   var b [N]int //b[i]:从beg到i的最短耗时
   queue := make([]int, 0)
   queue = append(queue, beg) //入队
   v := beg

   for v != end {
      v = queue[0]
      queue = queue[1:] //出队

      q1, q2, q3 := v-1, v+1, v*2
      if 0 < q1 && q1 < 2*end && b[q1] == 0 {
         b[q1] = b[v] + 1
         queue = append(queue, q1)
      }
      if 0 < q2 && q2 < 2*end && b[q2] == 0 {
         b[q2] = b[v] + 1
         queue = append(queue, q2)
      }
      if 0 < q3 && q3 < 2*end && b[q3] == 0 {
         b[q3] = b[v] + 1
         queue = append(queue, q3)
      }
   }

   return b[end]
}

func main() {
   //小青在n,小码在k
   var n, k int

   fmt.Scanf("%d%d", &n, &k)
   res := 0
   if n <= k { //小青前进可乘公交可步行
      res = bfs(n, k)
   } else { //小青向后走只能步行
      res += n - k
   }

   fmt.Printf("%d", res)
}

总结

该做法比较暴力,据测试当从0到100000时大概耗时3s+,抽象为图后,因为每个点之间的距离是1用dfs和bfs差不多,需要界定边界,因为乘公交时可达2X2*X的位置,而每次走路只能到前进后退1,所以当下个可达点超过2K2*K 了一定不是最优解。bfs可以不加边界,只判断到没到终点,因为一定可以到终点,且是最短耗时,但加上可以节省一点时空消耗,另外可达方式涉及不同的运算符,所以入队的时候写了三个判断,暂时没想到好的解决方法放到循环里。DP做法能力有限没想出来,待之后更(汗)。