bfs与剪枝的应用Catch That Cow——poj3278

描述

        农夫约翰被告知一头逃跑的奶牛的位置,并希望立即抓住她。他从数轴上的点 N (0 ≤ N ≤ 100,000) 开始,奶牛位于同一数字轴上的点 K (0 ≤ K ≤ 100,000) 处。Farmer John 有两种交通方式:步行和传送。

  •  行走:FJ 可以在一分钟内从任何 X 点移动到 - 1 或 + 1 点
  •  瞬移:FJ 可以在一分钟内从任何 X 点移动到 X 点 2 × 点。

如果这头奶牛不知道它的追赶,根本没有移动,那么 Farmer John 需要多长时间才能取回它?

输入

第 1 行:两个以空格分隔的整数:N 和 K

输出

第 1 行:Farmer John 抓住逃跑的奶牛所需的最短时间(以分钟为单位)。

样本输入

5 17

示例输出

4

提示

Farmer John 到达逃跑的奶牛的最快方法是沿着以下路径移动:5-10-9-18-17,需要 4 分钟。

问题分析

  • 本题是一道典型的bfs问题,主要是考察记忆化剪枝可行性剪枝,不是特别难(bushi),用普通队列和优先队列都可做,只是速度有差别:

  • 还有就是有些坑点,都写在代码里了
#include <cstring>
#include <cstdio>
#include<queue>
#include<iostream>
using namespace std;
int N, K; //农夫和奶牛一开始所处的位置

struct node {
    node() {}
    node(int ka,int st):x(ka),step(st){}
    int x;  //保存农夫现在所处的位置
    int step; //保存农夫从出发点开始走的步数
    //如果用priority这个是必加的
    bool operator < (node a)const {
        return step > a.step;
    }
};

//千万别忘了mp数组尽量开多一点,这个错找了好久(@_@!
bool mp[100003];

//本题用priority_que花费的时间空间都更少,虽然都能AC
priority_queue<node> que;
node now, nxt;

//直接switch,不找公式,简单粗暴
int cal(int i, int x) {
    switch (i) {
    case 1:
        return x - 1;
        break;
    case 2:
        return x + 1;
        break;
    case 3:
        return x * 2;
        break;
    }
}


void bfs() {
    while (!que.empty()) {
        now = que.top();
        que.pop();
        //找到答案,剪枝1 返回
        if (now.x == K) {
            cout << now.step << endl;
            return;
        }
        for (int i = 1; i <= 3; i++) {
            if (now.x > K && (i == 2 || i == 3))  continue;   //剪枝2,都超过奶牛了,就不要再向前走了
            nxt.x = cal(i, now.x);
            if (nxt.x < 0 || nxt.x>100000) continue;  //剪枝3,别过界 
            if (mp[nxt.x] == true) continue;  //剪枝4,如果这个位置在之前已经先到了,那么后到的花费的步数肯定更多,剪掉剪掉
            nxt.step = now.step + 1;
            que.push(nxt);
            mp[nxt.x] = true;
        }
    }
}

int main() {
    //天晓得他要多次输入啊,这个错找了我好久
    while (~scanf_s("%d%d", &N, &K)) {
        //剪枝5,后退的方式只有1种直接输出答案就行
        if (K <= N) {
            cout << N - K << endl;
            continue;
        }
        //每次循环都要先清理,再入队
        memset(mp, false, sizeof(mp));
        while (!que.empty()) {
            que.pop();
        }
        que.push(node(N, 0));
        mp[N] = true;
        bfs();
    }
    return 0;
}

//这是当时写剪枝的一些没用代码
/*if (now.x == K) {
    cout << 0 << endl; 本来想搞个特判,结果发现好像不用,哈哈
    return;
}
int mins = 10000000; //这个剪枝就纯属无厘头,当乐子看就行了,本来想提前结束,没处理好,没找到答案就结束了
if (now.x > K) {
    if ((now.step + now.x - K) < mins) {
        mins = now.step + now.x - K;
    }
    else continue;
}
if (now.x * 2 < K && now.x!=0)  i=3; //至于这个嘛,本来想用贪心算法思想的,但仔细想想,这题用贪心好像不行
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值