当青训营遇上码上掘金
题目描述:主题 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];
}
}