poj_3278_Catch That Cow(搜索广搜)

Catch That Cow
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 - 1 or + 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

Line 1: Two space-separated integers: N and K

Output

Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.

Sample Input

5 17

Sample Output

4

Hint

The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.

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);
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章