1. 程式人生 > >抓住那頭牛(POJ3278)

抓住那頭牛(POJ3278)

抓住那頭牛(POJ3278)

題目:
https://cn.vjudge.net/problem/POJ-3278

程式碼如下:

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define MAX 1000005

int step[MAX];
bool vis[MAX];
queue<int> q;

int bfs(int n,int k)
{
    int head,next;
    q.push(n);
    step[n] = 0;//初始位置花費時間0
    vis[n] = 0;
    while(!q.empty())
    {
        head = q.front();
        q.pop();
        for(int i = 0;i < 3;i++)
        {
            if(i == 0) next = head - 1;
            else if(i == 1) next = head + 1;
            else if(i == 2) next = head * 2;
            if(next < 0 || next >= MAX) continue;
            if(vis[next])
            {
                q.push(next);
                vis[next] = 0;//變成舊點
                step[next] = step[head] + 1;//每走一步花費時間加1
            }
            if(next == k) return step[next];//判斷該點是否為牛的位置
        }
    }
}

int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        memset(step,0,sizeof(step));
        memset(vis,1,sizeof(vis));
        if(n >= k) cout << n - k << endl;
        else cout << bfs(n,k) << endl;
    }
    return 0;
}

廣度優先搜尋(Breadth First Search)過程:
(1) 把初始節點S0放入Open表中;
(2) 如果Open表為空,則問題無解,失敗退出;
(3) 把Open表的第一個節點取出放入 Closed表,並記該節點為n;
(4) 考察節點n是否為目標節點。若是, 則得到問題的解,成功退出;
(5) 若節點n不可擴充套件,則轉第(2)步;
(6) 擴充套件節點n,將其不在Closed表和 Open表中的子節點(判重)放入Open表的尾部 ,併為每一個子節點設定指向父節點的指標( 或記錄節點的層次),然後轉第(2)步。
在這裡插入圖片描述

此題思路:
這道題要分為兩種情況,第一種就是牛在農夫左面(也就是n >= k)這個時候農夫最快的走法只能不停的每次往左邊移動一個,所以直接輸出n - k就是最少時間了。
第二種就是牛在農夫的右側,首先需要把數軸上每個點都初始化為1(也就是每個點都是新點)然後這個時候就要用bfs去求最短時間了。在bfs函式中首先把農夫的起始位置的座標放入佇列中,隨後從佇列中取出該值。然後列舉從這個點走向下一點所有可能的位置,如果這些位置都是新點並且都在範圍中則放入佇列中,然後把這些位置的點都變成舊點。並且走到這些點的時間等於上一個點所花時間加一。做完這些步驟後判斷該點的位置是否為牛的位置,如果是的就返回走到該點所花的時間,否則再接著搜尋。
簡單來說執行bfs是就是先把最初位置放入佇列,然後隊頭出隊,並且把從這個點走到下一個點可能的位置都放入佇列,然後此時再讓隊頭出隊,並把從這個點走到下一個點可能的位置都放入佇列,一直執行這個操作。