「青训营 X 码上掘金」寻友之旅

86 阅读2分钟

当青训营遇上码上掘金

寻友之旅

题目

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

思路

BFS找最短路

1、为什么是求最短路

问题转化: 以地点N为起点,地点K为终点,假设当前在点x,x只能向x+1,x-1,x* 2连边,所以每个点最多只会连三条边(单向变),同时有用的点最多只有200000个。每条边的权值为1,所以小青每走一步就相当于经过一条边,所以答案即为从N到K的最短路。

2、为什么有用的点最多只有200000个

  • 首先同一个点不必经过两次
  • 小青不必走到负数点,因为起始点为非负数,而负数点只能通过+1的方式到达K点,* 2只会越来越远。
  • 小青不必走到大于200000 因为往左走只能-1,起始点在100000以内,* 2之后必定在200000 以内,这个时候向左走的步数,一定比再* 2再向左走的步数少。

3、为什么BFS即可求出最短路 而不必使用如dijkstra等其他最短路算法

  • 当边权只有1时,可以用BFS求最短路。(结论)
  • 从原点开始遍历时,会将距离原点为1的点加入队列,然后开始顺序遍历队列中的点,此后队列中的点距离原点距离一定时递增的,因为只有遍历距离为x的点时,距离为x+1的点才会入队,而距离为x点得点遍历完,才会遍历x+1的点,所以所有结点入队时,距离原点距离一定是一直递增的。
  • 所以当终点第一次入队时,一定是最近的时候,下次遍历到一定更远,所以BFS可以求出最短路。

代码

import java.util.*;
public class Main{
    
    static int N = 200010;
    static int[] q = new int[N];
    static int[] dist = new int[N];

    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int k = scan.nextInt();
        
        int hh = 0,tt = -1;
        q[++tt] = n;
        dist[n] = 0;
        Arrays.fill(dist,-1);
        while(hh <= tt){
            int t = q[hh ++ ];
            if(t == k) break;
            if(t - 1 >= 0 && dist[t - 1] == -1){
                dist[t - 1] = dist[t] + 1;
                q[++ tt] = t - 1;
            }
            if(t + 1 < N && dist[t + 1] == -1){
                dist[t + 1] = dist[t] + 1;
                q[++ tt] = t + 1;
            }
            if(t * 2 < N && dist[t * 2] == -1){
                dist[t * 2] = dist[t] + 1;
                q[ ++ tt] = t * 2; 
            }
        }
        System.out.println(dist[k] + 1);
    }
}