POJ3278Catch That Cow BFS

本文详细解析了一道经典的算法题目“农夫抓牛”,通过使用广度优先搜索(BFS)算法,寻找农夫从起点到达固定不动的牛所在位置的最短路径。文章深入探讨了边界条件设置的重要性,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Catch That Cow

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 130721 Accepted: 40608
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 X - 1 or X + 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

问题连接

问题描述

农夫抓牛,农夫起始在点n处,牛在点k处,牛不动,农夫每分钟可以从点x处(他的位置),移动到x-1,x+1,或者2x的位置,问农夫最少花费多少时间能抓到牛。

问题分析

由于农夫在每一个地方可以选择三种行动方式,又是找最少花费时间,所以就想到了BFS,因为BFS有一个特点就是能输出操作数最少的解。如果想到BFS,那么基本上套模板就可以了,具体算法就不讲了。

p.x>=0&&p.x<k+5表示的是只取[0,k+5)范围的值,!vis[p.x]表示p.x处没有访问过,因为访问标记时就表示这时到这点是最早的,或是说操作数是最少的。
我当时写的时候没有写完边界条件,就是if (p.x >= 0 && p.x < k+5 && !vis[p.x]),我只写成了if(p.x>=0&&!vis[p.x]),导致一直错,因为如果不设置上界,那么有些情况乘2就会出现x比k大很多的情况,这时再加1,减1,乘2的操作就变得没有意义,放入队列只是浪费运行的时间和空间。
这里提一下,上界为什么设置成k+5呢?我看了很多人的题解里都是写成100005或者1000010,当时很是不理解为什么是这样?最后画了个数轴就想明白了。
下面简单地做了个数轴:
————————————————————>
0____________half____________k________
举个例子:如果农夫在51,k为100,那么最快的方法是先减到1再乘2,即51到50到100.
如果是先乘2,那么就变成了51到102到101到100,比之前的方法多走了一步,显然在[51,99]这个一块区域里先乘2再减到100的操作数是一定比先减到50再乘2到100的操作数多的。当然[75,99]这段用+1可以更快。
但是如果情况是农夫在50,k为99,那么先减1到49(向下取整),再乘2到98,再加1到99用了3步;而可以先乘2到100在减1到99,只用了2步。所以有效的上限是k+1,为了看起来舒服我取了k+5。

其实,说来这么多,我只是想把上限的取值原因弄明白。如果真要细说,0到half这段,如果half很大,那么一些区间内每次都是+1或者-1也变的不太合理,但是真要细化会很麻烦,所以把它当个简单的搜索题吧。

c++程序如下

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int MAX = 100005;
int n, k;
bool vis[MAX];
struct state
{
	int x, time;
}q,p;
void bfs();
int main()
{
	cin >> n >> k;
	if (n > k) cout << n - k << endl;//只能减,那么直接输出就行了
	else bfs();
	return 0;
}
void bfs()
{
	memset(vis, 0, sizeof(vis));
	queue<state>Q;
	q.x = n;
	q.time = 0;
	Q.push(q);
	vis[q.x] = 1;
	while (!Q.empty())
	{
		q = Q.front();
		Q.pop();
		if (q.x == k)
		{
			cout << q.time << endl;
			return;
		}
		for (int i = 0; i < 3; i++)
		{
			if (i == 0) p.x = q.x + 1;
			else if (i == 1) p.x = q.x - 1;
			else p.x = q.x * 2;
			if (p.x >= 0 && p.x < k+5  && !vis[p.x])//边界条件和访问标记
			{
				vis[p.x] = 1;
				p.time = q.time + 1;
				Q.push(p);
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值