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


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