Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 109183 | Accepted: 34100 |
Description
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?
Input
Output
Sample Input
5 17
Sample Output
4
Hint
Source
题目大意:
开始输入N(FJ的位置)K(奶牛的位置)。
FJ有三种移动方法:1、向前走一步,耗时一分钟、
2、向后走一步,耗时一分钟。
3、向前移动到当前位置的两倍N*2,耗时一分钟。
问FJ抓到奶牛的最少时间。PS:奶牛是不会动的。
分析:利用队列,每次可以将三种不同的走法的结果都入队,像是一个三叉树,每个节点有三个不同的子节点。依次出队每个节点判断是否可以到达终点,记录步数(找到终点的步数就是最优的)输出即可。
AC代码:
C++:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue> //广搜使用队列
using namespace std;
int n,k;
int step[100005];
int book[100005];
queue <int >Q;
int bfs(int n,int k)
{
int head,next;
Q.push(n); //把起点入队
step[n] = 0; //用一个数组记录
book[n] = 1; //用数组标记经过的点
while(!Q.empty()) //队列不为空
{
head = Q.front(); //出队第一个元素
Q.pop(); //删除
for(int i=0;i<3;i++) //每个点有三种不同的走法,分别用不同的来代替一下
{
if(i == 0) //等于0执行减1 操作
next = head-1;
else if(i == 1) //等于1执行+1
next = head+1;
else if(i == 2) //等于2执行*2
next = head*2;
if(next < 0 || next >= 100001) //超出某个范围的继续下一轮
continue ;
if(book[next] == 0) //判断该数字是否被标记过
{
Q.push(next); //没有就入队
step[next] = step[head]+1; //步数加1(在父节点的基础上加1 ,一个点延伸出的三个子节点都是在一个父节点的步数基础上加1)
book[next] = 1; //标记,这里不用取消标记,因为不用再回去找,也不会有别的可能了
}
if(next == k) //子节点中有一个点的值与终点的相同就结束输出结果
return step[next];
}
}
return 0;
}
int main()
{
scanf("%d%d",&n,&k); //从N到k需要的步数
if(n >= k) //起始点在终点右边,只能通过减到达终点
{
printf("%d\n",n-k);
return 0;
}
int num = bfs(n,k); //否则的话广搜找步数,类似三叉的树,每个节点有三种不同的方法去走。
printf("%d\n",num);
return 0;
}
Java:
import java.util.*;
public class Main{
static int maxx = 1000005;
static int que[] = new int [maxx];
static int step[]= new int [maxx];
static int book[] = new int [maxx];
static int head,tail;
public static int bfs(int n,int k) {
int next = 0;
head = 1;
tail = 1;
que[head] = que[tail] = n; //队列就是建立在数组的基础上的C++中的STL可以转换成数组来做
step[n] = 0;
book[n] = 1;
tail ++;
while(head < tail )
{
int cur = que[head]; //一个父节点
for(int i=0;i<3;i++) //产生三个子节点
{
if(i == 0)
next = cur-1;
else if(i == 1)
next = cur+1;
else if(i == 2)
next = cur*2;
if(next < 0 || next >= 100005) //超界的情况
continue ;
if(book[next] == 0) //没有访问过该位置
{
que[tail] = next; //把该位置入队
tail ++; //后移一个,方便下一次插入
step[next] = step[cur]+1; //子节点的步数是在父节点的基础上加1
book[next] = 1; //标记已经走过
}
if(next == k) //当找到结果,就返回
return step[next];
}
head ++;
}
return 0;
}
public static void main(String [] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
if(n >= k) //终点在起点左边,要能够到达终点则只能往左走,即减小
System.out.println(n-k);
else
{
int m = bfs(n,k); //广搜
System.out.println(m);
}
}
}