寻友之旅(动态规划)

59 阅读1分钟

当青训营遇上码上掘金

主题 3:寻友之旅

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

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

作者:青训营官方账号
链接:juejin.cn/post/718775…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路(动态规划)

小青(N)可以通过三种方式到达小码(K)的位置,分别是X+1、X-1、2*X。

  • 当小青在小码前面时,即N > K, 只能通过X-1的方式步行到小码家
  • 当小青在小码后边时,即N < K
    • 步行过去(X + 1)
    • 公交过去
      • 若 X % 2 == 0,直接坐公交(X * 2)
      • 若 X % 2 != 0,先向前走一个节点或者向后走一个节点,然后再坐公交((X+1)2,(X-1) 2 )

状态表示:使用一个数组f[100001],存储从N到i的最短距离。

从位置N出发,向左只能步行,向右直到100000,通过动态规划寻找最小值,最后返回f[K]即可。

import java.util.*;

public class Main {
  static int N = 100010;
  static int [] f = new int [N]; // 表示从n到i需要的最短时间
  
  static int main_time(int n, int k) {
      
      // 初始化状态
      f[n] = 0;//从n到n花费的时间为0
      int res =  Integer.MAX_VALUE;
      
      for (int i = n - 1; i >= 0; i--) 
      {
        f[i] = f[i + 1] + 1; //在n左边的位置只能通过步行去
      }
      // 限定范围从0 ~ 100000,从n到k,最多可能从100000步行到k
        for (int i = n + 1; i <= 100000; i++) {
            // 步行
            int walk = f[i - 1] + 1; 
            //坐公交
            
            int bus = f[i / 2] + 1; 
            // 如果不能直接坐公交,先向前或向后步行一个位置
            if (i % 2 != 0) { 
                bus = Math.min(f[(i + 1) / 2], f[(i - 1) / 2]) + 2;
            }
            
            f[i] = Math.min(walk, bus);
            
            if (i >= k) {
                res = Math.min(res, f[i] + i - k);
            }
        }
    
          return res;
      }
  
  public static void main(String [] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int k = sc.nextInt();
    System.out.println(main_time(n, k));
  }  
}