当青训营遇上码上掘金
寻友之旅
题目
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 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);
}
}