咸鱼翻身之路——我与农夫和牛的故事

在前几天,本咸鱼认识了一个魔法师农夫,但他只对他的牛感兴趣,于是就有了一个有趣(才怪)的问题:
农夫约翰已被告知一头逃亡牛的下落,并希望立即抓住她。他从数字线上的N点(0≤N≤100,000)开始,牛在同一数列上的K点(0≤K≤100,000)。农民约翰有两种运输方式:步行和传送。

*步行:FJ可以在一分钟内从任何X点移动到X-1点或X+1点。
*传送:FJ可以在一分钟内从任何X点移动到2×X点。

如果母牛没有意识到它的追求,根本不动,农场主约翰需要多长时间才能找回它?

输入
第1行:两个空格分隔的整数:n和K

输出量
第1行:最短的时间,在几分钟内,农夫约翰就能抓住逃亡的母牛。

样本输入
5 17

样本输出
4
暗示
农夫约翰找到逃亡牛的最快方法是沿着以下的道路移动:5-10-9-18-17,这需要4分钟。

这道题乍一看是最短路问题,但仔细想想,发现它的核心其实是bfs,但是我还是差点被搞死,不会做啊啊啊啊啊啊,最后还是大佬拉了我一把,给我讲了一下这题的思路(感谢大佬救命之恩),粘一下大佬的代码

#include<bits/stdc++.h>
using namespace std;
int book[10000]={0},mk[1000];//book标记走过的点,mk来计算一共走了多少步
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);//关闭c语言的输入输出来提速
	int m,n;
	cin>>n>>m;
	if(n==m){
		cout<<0;
		return 0;
	}
	queue<int>q;//这里用了queue函数,下面会介绍
	q.push(n);//将农夫当前位置入队
	book[n]=1;
	while(q.size()){
		int p=q.front();//将农夫位置赋给p
		q.pop();//农夫位置出队
		int pp;
		for(int i=1;i<=3;i++){//枚举三种情况
			if(i==1)
				pp=p+1;//记录农夫下一步的位置,下同
			else if(i==2)
				pp=p-1;
			else if(i==3)
				pp=p*2;
			if(book[pp]==0&&pp>=0&&pp<=100000){//查看下一步的位置是否符合要求
				mk[pp]=mk[p]+1;//当前步数=走到上一个点的步数+1
				book[pp]=1;//标记这个点已经走过
				if(pp==m){//判断农夫是否找到了牛
					cout<<mk[pp];
					return 0;
				}
				q.push(pp);//没找到牛将当前位置入队再往下继续查找
			}
		}
	}
} 

本咸鱼认为这个题queue函数是比较关键的一部分,奈何不会,只好去现学了一下,大概知道了queue函数的部分用法,在这里分享一下

queue函数

1、push()
队列中由于是先进先出,push即在队尾插入一个元素

queue<string> q;
q.push("Hello World!");
q.push("China");
cout<<q.front()<<endl;

最后输出:Hello World!

2、pop()
将队列中最靠前位置的元素拿掉,是没有返回值的void函数

queue<string> q;
q.push("Hello World!");
q.push("China");
q.pop();
cout<<q.front()<<endl;

最后输出:China

原因是Hello World!已经被除掉了。

3、size()
返回队列中元素的个数,返回值类型为unsigned int

queue<string> q;
cout<<q.size()<<endl;
q.push("Hello World!");
q.push("China");
cout<<q.size()<<endl;

输出两行,分别为0和2,即队列中元素的个数

4、empty()
判断队列是否为空的,如果为空则返回true

queue<string> q;
cout<<q.empty()<<endl;
q.push("Hello World!");
q.push("China");
cout<<q.empty()<<endl;

输出为两行,分别是1和0。因为一开始队列是空的,后来插入了两个元素

5、front()
返回值为队列中的第一个元素,也就是最早、最先进入队列的元素。注意这里只是返回最早进入的元素,并没有把它剔除出队列

queue<string> q;
q.push("Hello World!");
q.push("China");
cout<<q.front()<<endl;
q.pop();
cout<<q.front()<<endl

输出值为两行,分别是Hello World!和China。只有在使用了pop以后,队列中的最早进入元素才会被剔除!!

6、back()
返回队列中最后一个元素,也就是最晚进去的元素

queue<string> q;
q.push("Hello World!");
q.push("China");
cout<<q.back()<<endl;

输出值为China,因为它是最后进去的。这里back仅仅是返回最后一个元素,也并没有将该元素从队列剔除掉

这部分queue函数的用法我是从另一位大佬的博客那里学的,然后简单整理了一下方便看懂,要是还有什么疑问的话可以去大佬博客转转
大佬空间的传送门

懂了queue函数之后这个题应该就简单很多了,剩下的就是思路问题了

教我这个题的大佬他是用bfs一步步往下找最短,每找一次就枚举三种情况并标记,防止查重,然后每种情况走的步数为之前走的步数+1,当农夫找到牛后,就输出总步数然后结束程序
这里有一点需要注意,就是怎么判断输出的一定是最短路呢,因为bfs是同时往下搜索的,如果农夫没找到牛,bfs就会继续往下搜索,所以我们每往下搜索一次就应该判断一次农夫是否找到牛,因为按照bfs的思想,最先找到牛的路就是最短路,所以输出第一个找到牛的步数就行了

这个题的最优解应该是bfs,dfs是一条路走到黑,假如用dfs做的话会有很多种情况,必须要剪枝(不仅麻烦而而且我也不会…),而且你每一条路都走到黑,不一定什么时候才能碰到最短路的值,最不济都可能会爆栈,所以不推荐用dfs做(才不告诉你是因为我和大佬都没用dfs做出来

题外话:
大佬又又又告诉我这是一道裸的不能再裸的题,哇,我是真的咸,万一那天大佬把我踹了我岂不是就凉凉了吗,看来我得赶紧多练练基础题了,争取抱紧大佬大腿,实现咸鱼翻身!!

发布了37 篇原创文章 · 获赞 16 · 访问量 6067

猜你喜欢

转载自blog.csdn.net/qq_44039966/article/details/84986373
今日推荐