~~一个常年拒绝思考的混吃等死选手~~
题目是这样的:
> 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.
[题目连接](http://poj.org/problem?id=3278)
某杜一看,不难,就是抓牛嘛,和某杜最擅长的摸鱼没差。
稍微思考了一会儿发现:不对劲!即使看懂了题目、笔算也能算出来,可是感觉缺少了什么、写不出程序。
于是某杜带着题请教了教练,没一会儿教练回复了几个词:
简单搜索、BFS、菜。
BFS?BFS我懂啊,BFS不是图里面的吗?这题还得用图啊?
一会儿教练又回了:
百度去
某杜百度回来以后大彻大悟:原来是这个意思。
先上代码:
```
#include<stdio.h>
#include<string.h>
#include<queue>
#define max 100005
using namespace std;
int n,k;
struct node{
int x;
int step;
}q[max];
int flag[max];
void bfs(){
int i;
node now,next;
int head=0,tail=0;
q[head].x=n;
q[head].step=0;
tail++;
flag[n]=1;
while(head<tail){
now=q[head];
head++;
for(i=0;i<3;i++){
if(i==0){
next.x=now.x-1;
}
else if(i==1){
next.x=now.x+1;
}
else{
next.x=now.x*2;
}
if(next.x<0||next.x>100001){
continue;
}
if(flag[next.x]==0){
flag[next.x]=1;
next.step=now.step+1;
q[tail].x=next.x;
q[tail].step=next.step;
tail++;
if(next.x==k){
printf("%d
",next.step);
}
}
}
}
}
int main(){
while(scanf("%d %d",&n,&k)!=EOF){
memset(flag,0,sizeof(flag));
if(n>=k){
printf("%d
",n-k);
}
else{
bfs();
}
}
return 0;
}
```
有结构体数组、head和tail,是一个队列跑不了,但是先说说这究竟是怎么一回事。
在某杜的理解下,这类搜索题一共有两个要点:
**1、上一个状态和下一个状态**
**2、上一个状态如何变到下一个状态**
是不是和动态规划有异曲同工之妙,只不过某杜对动态规划的理解还止步于状态和状态转移方程,所以不敢多说什么。硬要说的话应该是**BFS搜索通过略暴力的方式把所有符合条件的情况都算了一遍,直到某一次的运算结果符合了题目的输出要求才停止运算输出结果,这其中由初始状态到目标状态的路子有很多种。**
打个比方,如果没有题目限制,由2到10,我可以每次加1加8次,我可以每次加2加4次,我还可以每次乘5乘一次。
然而BFS搜索题总会给你一个或者几个题目要求,比如要求你只能每次加1和每次加2或者只能每次加1和每次乘5。
理解了很好理解的这些以后再看题简直太简单,题目说的清清楚楚,FJ每次可以往前走1或者往后退1或者一次乘2。
然后就是存储和使用数据的形式,其实也不难想,我**需要用到现在的状态去算下一个状态**,拿题目来说,刚开始FJ站在5,FJ往前走一步走到了6,FJ往后退一步退到了4,FJ Teleporting 了一下到了10,然后把6、4、10这三个量存一下,5就不需要了。这很明显符合队列的存取特征,那就用队列呗。
还有一些细节,比如FJ已经在0了,如果再往后退1显然不符合常理,再比如FJ Teleporting过了头,Teleporting出了最大范围,这也不需要再算了,直接砍掉。
还有假如FJ已经由5通过Teleporting到过了10,那么FJ就不需要再记录由5通过每次走1走到10花了多少次,因为第二次到10肯定比第一次用的步数多。
理解了这一道题以后,某杜又找了一些别的简单搜索题写,差不多就是换个皮,做法和抓牛一样。
某杜学会了,某杜企图向教练炫耀——教练说,还有一堆儿搜索进阶题呢,慢慢写吧。。