在前几天,本咸鱼认识了一个魔法师农夫,但他只对他的牛感兴趣,于是就有了一个有趣(才怪)的问题:
农夫约翰已被告知一头逃亡牛的下落,并希望立即抓住她。他从数字线上的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做出来)
题外话:
大佬又又又告诉我这是一道裸的不能再裸的题,哇,我是真的咸,万一那天大佬把我踹了我岂不是就凉凉了吗,看来我得赶紧多练练基础题了,争取抱紧大佬大腿,实现咸鱼翻身!!