抓住那头牛(宽搜bfs)

Description
农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N,牛位于点K。
农夫有两种移动方式:
1.从X移动到X−1或X+1,每次移动花费一分钟。
2.从X移动到2∗X,每次移动花费一分钟。
假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?
Input
第一行为两个整数,分别为N和K。
Output
一个整数,农夫抓到牛所要花费的最小分钟数。
Sample Input 1
5 17
Sample Output 1
4
Hint
0<=N<=100000
0<=K<=100000
Time Limit
1000MS
Memory Limit
256MB

分析:由题意求农夫抓到牛的最短时间,便知此题是宽搜。我们可以把农夫的坐标和已经花费的分钟数打包成一个状态,作为宽搜的结点。同时由于这题的特点,先搜索到一定花时间更短,没必要重复搜索,因此这题可以根据坐标是否搜索过剪枝。
参考代码:

#include<stdio.h>
#include<queue>
using namespace std;

struct state//状态打包
{
    
    
    long long int x;//坐标
    long long int t;//时间
    void operator=(const state &s)
    {
    
    
        x=s.x;
        t=s.t;
    }
    state(){
    
    }
    state(long long int X,long long int T)
    {
    
    
        x=X;
        t=T;
    }
};

queue<state> q;
long long int n,k;//农夫起始点,牛坐标
bool vis[200001]={
    
    0};//标记已经搜索过的坐标

int main()
{
    
    
    scanf("%lld%lld",&n,&k);

    if(n>=k){
    
    //农夫在牛右边,只能以X-1的方式向左移动抓牛
        printf("%lld",n-k);
        return 0;
    }

    state head;//接收队头结点
    long long int dos,time;//队头结点的坐标、时间
    q.push(state(n,0));//加入农夫初态
    vis[n]=true;//标记农夫初位置
    while(!q.empty())
    {
    
    
        head=q.front();
        q.pop();
        dos=head.x,time=head.t;
        if(dos==k){
    
    //已经到牛的位置了,退出搜索
            printf("%lld",time);
            break;
        }
        //一定要 先判断数组越界 再判断重复搜索!
        if(dos+1<=200000 && !vis[dos+1]){
    
    
            vis[dos+1]=true;
            q.push(state(dos+1,time+1));
        }
        if(dos-1>=0 && !vis[dos-1]){
    
    
            vis[dos-1]=true;
            q.push(state(dos-1,time+1));
        }
        if(2*dos<=200000 && !vis[2*dos]){
    
    
            vis[2*dos]=true;
            q.push(state(2*dos,time+1));
        }
    }
    return 0;
}

易错点总结:要先判断数组越界再判断重复搜索。举个例子:如果这么写if(!vis[dos-1] && dos-1>=0),当dos=0,dos-1=-1,下标已经越界,但是程序会先走!vis[dos-1],从而发生了数组越界访问,导致某些oj评测点结果为Runtime Error。

猜你喜欢

转载自blog.csdn.net/qq_44643644/article/details/105901538