【青训营 X 码上掘金】 主题三

58 阅读1分钟

当青训营遇上码上掘金

题目描述:主题 3:寻友之旅

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

请帮助小青通知小码,小青最快到达时间是多久?

输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

解题思路:

本题目有多种解题方法:因结果只出现一次,因此可以选择贪心算法。还可选择广度优先搜索算法(BFS),还看到过有人使用堆优化的迪杰斯特拉算法。

我首先想到dp数组,动态规划。

  • 当N>K时,小青在小码前面,小青只能步行前往。结果为N-K;
  • 当N<K时,首先明确一个问题:若公交车落点也在终点之前,公交车速度大于等于步行。
    • n<k/2时:乘坐公交车优于步行,最差的结果也是和步行同速。因此若n<k/2,永远选择公交车;
    • k>n>k/2时:解一下此不等式,当k= n/2 + n时,达到临界值,得出以下结论。
      • k > n/2 + n 时,dp[k] = dp[k/2] + k%2 + 1;
      • k <= n/2 + n时,dp[k] = dp[k-1] + 1。

附Java代码:

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int k = scan.nextInt();
        System.out.println(dp(n,k));
    }
    private static int dp(int n, int k) {
        if (k <= n){
            return n - k;
        }
        int[] arr = new int[k+1];
        int count = 1;
        for (int i = n - 1; i >= 0; i--) {
            arr[i] = count++;
        }
        arr[n] = 0;
        arr[n+1] = 1;
        for (int i = n + 2; i <= k; i++) {
            if ( i - n <= n/2){
                arr[i] =arr[i - 1] + 1;
            }else {
                arr[i] =arr[i/2] + i % 2 + 1;
            }
        }
        return arr[k];
    }
}