题目大意:一条x轴,一个人在n位置,牛在m位置,他要抓牛,牛不会动。他只会向前一步,向后一步或跨到当前坐标的两倍位置。问最少他要走几步。
解题思路:看着林炜代码,一行一行敲。。。首先,由于牛不会动,所以当用bfs中第一次碰到牛时,步数是最少的。解释如下:bfs中的循环,第一次是第一步能到的距离,第二次是第一步到的距离的第一个入队的第二步能到的距离,第三次是第一步到的距离的第二个入队的第二步能到的距离....以此类推。一个标记数组,初值为-1,非-1表示走过,不能再走(上面已经介绍第一次到达某位置,是步数最少的,所以不再走),标记数组也是计步数组,因为走过以后非-1,自然可以作为步数保存起来。循环之前,将人的位置的标记数组值赋为0,表示他不能会这个位置,因为这是浪费步数。将人的位置入队,这是人的第一步开始的地方。循环开始,将队列第一个出队传给变量,然后队列中删去(以后就走不到了),判断是否到达位置,到达则返回标记数组的值(步数),未到达则说明在牛之前,或牛之后,在牛之后,则只能一种操作后退,任何操作之前到要判断将移动的点是否走过,如果没走过进行操作,即记录步数,入队。
ac代码:
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n, k;
queue <int> qu;
int vis[200010];
int bfs()
{
memset(vis, -1, sizeof(vis));
int head=0, fail=0, p;
while (!qu.empty())
qu.pop();
qu.push(n);
vis[n] = 0;
while (!qu.empty()){
n = qu.front();
qu.pop();
if (n == k)
return vis[n];
if (n > k){
p = n - 1;
if (vis[p] == -1 && p >= 0){
vis[p] = vis[n]+1;
qu.push(p);
}
}
else {
p = 2 * n;
if (vis[p] == -1 && p < 200010){
vis[p] = vis[n] + 1;
qu.push(p);
}
p = n + 1;
if (vis[p] == -1 && p <200010){
vis[p] = vis[n] + 1;
qu.push(p);
}
p = n - 1;
if (vis[p] == -1 && p >= 0){
vis[p] = vis[n] + 1;
qu.push(p);
}
}
}
}
int main()
{
while (scanf("%d%d", &n, &k)!=EOF)
printf("%d\n", bfs());
return 0;
}