主题介绍
主题 3:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
1. 思路
小青和小码的位置在同一条直线上,这里可以把二者想象成数轴上的两个点(N,0),(K,0)
我们需要研究小青到达小码家的最短步骤,就需要明白二者位置的具体关系。
即分为 N<K,N>K 的两种具体情况(当N=K时,直接返回0即可)
2. 解题方法
此题容易让人联想到采用动态规划,因为需要判断每一步的最优情况。
- 当N>K时,此时题目中所给的移动方式,只能采取步行向后慢慢靠近小码家,
易知dp[i] = dp[i-1] + 1; - 当N<K时,这里两种交通方式都可以采用。我们需要做出进一步的判断,到底选择哪一种交通方式更合理。
容易想到的是,若n<k/2,选择公交的方式是最佳的,顶多也是和步行持平(N=1)
所以解题的关键就是出在k>n>k/2这个区间范围之间
结合题目所给步行进退速度都为1可知,当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。
3. Code
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));
}
//arr[i]为小青到目的地所需要的最短时间
private static int dp(int n, int k) {
//小码在小青的前面,k<=n时
if (k <= n){
return n-k;
}
//小青在小码的后面,k>n时
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];
}
}
附录
以上解题思路偏数学化,再用另外一种方法解题,详见代码
本题也同时可以使用BFS暴力搜索,因为每个值只会出现一次