描述
农夫约翰被告知一头逃跑的奶牛的位置,并希望立即抓住她。他从数轴上的点 N (0 ≤ N ≤ 100,000) 开始,奶牛位于同一数字轴上的点 K (0 ≤ K ≤ 100,000) 处。Farmer John 有两种交通方式:步行和传送。
- 行走:FJ 可以在一分钟内从任何 X 点移动到 X - 1 或 X + 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; //至于这个嘛,本来想用贪心算法思想的,但仔细想想,这题用贪心好像不行
*/