题目
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
- Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
- Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
翻译:奶农要抓牛,他们在一条线上,一次可以往左或者往右移动一步,或者直接心灵传送到2倍当前位置。问最少需要几步能抓到奶牛?
Input
Line 1: Two space-separated integers: N and K
输入N(奶农)位置,K(奶牛位置)
Output
Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.
输出最小抓到奶牛的步数。
思路
广搜,广搜搜到了就是最优值,而且复杂度还小。
搜索题目,最主要是确定搜索边界和如何扩展节点。
当奶农位置大于奶牛的时候,我们只有一种往左移动的情况,就是一个位置一个位置慢慢走,所以,可以判断一下,当这种情况,直接输出即可,不用再去搜索了。
当奶牛在奶农右边的时候,我们可以利用三种情况不断扩展可能到达的节点进入队列之中。当N<K时,所以,我们需要确定边界。至于边界是什么?
右边界,因为当我们超出了奶牛的位置的时候,只能一个格子一个格子往左走了,所以,最多也就只能到(K+(K-N))的位置,因为从那里,我们直接一个一个往左走,那还不如直接我们从一开始就往右走;
左边界,最多也就只能到(N-(K-N)),我们也是一个道理。然后进行广搜,找到了就可以了!
代码
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class Point
{
int x;//坐标
int step;//步数
}
public class Main{
static int N;//起点
static int K;//终点
static Queue<Point> queue=new LinkedList();
static int visited[]=new int[200009]; //标记数组
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
N=reader.nextInt();//接收起点
K=reader.nextInt();//接收终点
if (K<=N) {
System.out.println(N-K);
return;
}
queue.clear();//清空队列
int end=K+K-N;
for (int i=0;i<=end;++i)
visited[i]=0;
//队头节点入队
Point temp=new Point();
temp.x=N;
temp.step=0;
queue.offer(temp);
visited[N]=1;
while (!queue.isEmpty())
{
int front_x=queue.peek().x;
int front_step=queue.peek().step;
if (front_x==K) {
System.out.println(front_step);
break;
}
//扩张右边点
if (front_x+1>=0 && front_x+1<=end && visited[front_x+1]==0)
{
Point b=new Point();
b.x=front_x+1;
b.step=front_step+1;
queue.offer(b);
visited[front_x+1]=1;
}
//扩展两倍节点
if (front_x*2>=0 && front_x*2<=end && visited[front_x*2]==0)
{
Point c=new Point();
c.step=front_step+1;
c.x=front_x*2;
queue.offer(c);
visited[front_x*2]=1;
}
//扩张左边点
if (front_x-1>=0 && front_x-1<=end && visited[front_x-1]==0)
{
Point a=new Point();
a.step=front_step+1;
a.x=front_x-1;
queue.offer(a);
visited[front_x-1]=1;
}
queue.poll();//弹出队首
}
}
}
结果
ac了,但是这道题踩了不少坑,也算有收获的。
对于,深搜和广搜,不仅仅只会做那些迷宫的题目了,只要能找到边界和往下搜索的条件就可以进行搜索!
对于数组而言,题目要求是10w,那么标记数组一定要开20w,因为有个两倍的,就是 K和 N同时是10w,数组这样子也不会越界!