1. 程式人生 > >POJ 3278 Catch That Cow 【bfs+佇列】

POJ 3278 Catch That Cow 【bfs+佇列】

演算法:bfs+佇列+STL(C++)

PS:bfs入門題目,好高興啊,終於會用bfs了。大笑

Catch That Cow
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 32679 Accepted: 10060

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

題意:

          FJ要抓奶牛。

         開始輸入N(FJ的位置)K(奶牛的位置)。

         FJ有三種移動方法:1、向前走一步,耗時一分鐘。

                                              2、向後走一步,耗時一分鐘。

                                             3、向前移動到當前位置的兩倍N*2,耗時一分鐘。

       問FJ抓到奶牛的最少時間。PS:奶牛是不會動的。

思路:1、如果FJ不在奶牛後面,那麼他只有一步步往後移動到奶牛位置了,即N>=K時,輸出N-K即可。

          2、否則bfs+佇列查詢(具體見下面的分析&&程式碼區)

相關演算法:

            1、STL中的佇列。(PS:週四才在資料結構上了解bfs的真正思想,慚愧啊!)

                需要的標頭檔案:STL是C++中的 #include<iostream>

                                                                 using namespace std;

                                         queue佇列容器的標頭檔案 #include<queue>

               queue佇列的相關用法:先進先出(FIFO)

                                                     入隊push()   //即插入元素

                                                     出隊pop()    //即刪除元素

                                                     front()        //讀取隊首元素

                                                     back()       //讀取隊尾元素

                                                     empty()     //判斷佇列是否為空

                                                     size()        //讀取隊列當前元素的個數         

              2、bfs思想:節點進行廣度優先搜尋的順序。

                                                                         

                               搜尋實現方法(非遞迴):

                               演算法思想:1.設定一個佇列Q,從頂點出發,遍歷該頂點後讓其進隊;

                                                 2.出隊一個頂點元素,求該頂點的所有鄰接點(對應於此題即FJ的三種走法),

                                                    對於沒有遍歷過的鄰接點遍歷之,並 讓其進隊;

                                                 3.若隊空停止,隊不空時繼續第2步。

看了牛人部落格後的程式碼,總算了解bfs了,Orz

程式碼一:C++STL&&bfs版本:

PS :很奇怪在POJ中AC了,今天交到hdu中去WA了,後來問了KB神才知道是沒有清空佇列,POJ是單組輸入的。而陣列模擬的不存在這個問題是因為每        次呼叫bfs陣列下標都是從0開始的。

       還有就是佇列清空不存在 q.clear(); 要用 
        while(!q.empty()) q.pop(); //注意呼叫前要先清空
  

//Accepted	984K	79MS	C++	1128B	2012-11-10 00:44:26
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn=100001;

bool vis[maxn];//標記陣列
int step[maxn];//記錄到了每一位置所走的步數
queue <int> q;//定義佇列

int bfs(int n,int k)
{
    int head,next;
    q.push(n);   //開始FJ在n位置,n入隊
    step[n]=0;
    vis[n]=true; //標記已訪問
    while(!q.empty())  //當佇列非空
    {
        head=q.front();  //取隊首
        q.pop();         //彈出對首
        for(int i=0;i<3;i++)     //FJ的三種走法
        {
            if(i==0) next=head-1;
            else if(i==1) next=head+1;
            else next=head*2;
            if(next<0 || next>=maxn) continue; //排除出界情況
            if(!vis[next])  //如果next位置未被訪問
            {
                q.push(next);    //入隊
                step[next]=step[head]+1;  //步數+1
                vis[next]=true;  //標記已訪問
            }
            if(next==k) return step[next];  //當遍歷到結果,返回步數
        }
    }
}
int main()
{
    int n,k;
    while(cin>>n>>k)
    {
        memset(step,0,sizeof(step));
        memset(vis,false,sizeof(vis));
        
        while(!q.empty()) q.pop(); //注意呼叫前要先清空
        if(n>=k) printf("%d\n",n-k);
        else printf("%d\n",bfs(n,k));
    }
    return 0;
}


程式碼二:C語言+bfs+模擬佇列版本 hdu 和poj都能AC
//Accepted	736K	0MS	C++	1017B	2012-11-10 04:24:09
#include<stdio.h>
#include<string.h>
const int maxn=100001;
bool vis[maxn];
int n,k;
struct Node
{
    int x,step;
};
Node q[maxn];
int bfs()
{
    int i;
    Node now,next;
    int head,tail;
    head=tail=0;
    q[tail].x=n;
    q[tail].step=0;tail++;
    vis[n]=true;
    while(head<tail)
    {
        now=q[head];//取隊首
        head++;//彈出對首
        for(i=0;i<3;i++)
        {
            if(i==0) next.x=now.x-1;
            else if(i==1) next.x=now.x+1;
            else next.x=2*now.x;
            if(next.x<0 || next.x>=maxn) continue;//剪枝、排除越界
            if(!vis[next.x])
            {
                vis[next.x]=true;
                next.step=now.step+1;
                q[tail].x=next.x;q[tail].step=next.step;tail++;
                if(next.x==k) return next.step;
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(vis,false,sizeof(vis));
        if(n>=k) printf("%d\n",n-k);
        else printf("%d\n",bfs());
    }
    return 0;
}