[bfs] 红红去小寨(bfs 求最短路+思维)

题目描述

红红今天中午想去市中心吃饭,他决定坐公交车去。但是去公交车的时候红红决定练习一下空间魔法,穿梭时空

现在红红到公交车的路是一条直线,然后他可以通过三种方式移动:

  1. 向前走一个位置

  2. 向后走一个位置

  3. 空间移动,将自己的位置从 x 移动到 2 * x

三种移动方式都需要 10 s

但是红红希望能尽量减少体力的消耗, 所以他希望能以最短的时间到达公交车站

输入

有多组测试样例

每组测试样例包括一个 nk ( 0 < n, k<= 100000)

n 表示红红目前的位置

k 表示公交车站的位置

输出

输出公交车站所需要的最小用时,输出 x:x (表示几分几秒)

样例输入

5 17
7 4
5 10000

样例输出

0:40
0:30
2:10

提示

N 可能大于 K


分析与代码

以前遇到的题目大多都是 *2,+1 / -1+1-1 两种操作不会同时出现,采用逆推的方式就能解决该问题。但是本题缺无法逆推,因为无法确定的知道奇数情况下是通过 +1 还是 -1 变成偶数情况的。

本题操作步数越小越好,且每步操作可看作权值一样,都是只能选择三种方案的其中一种,故可以进行 bfs,得到转换操作的最小步数即可。

代码采用数组模拟队列,dist 数组有三种状态,初始化为 -1 表示该数字不能到达,起点值为 0,每一步的转换更新 dist 数组即可。即优化掉了判重数组,dist 同时完成了判重+记录转化步数的功能,也是常见技巧。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
 
using namespace std;
 
const int N = 100005;
 
int q[N];
int n, k;
int res;
int dist[N];
 
void bfs(int x) {
    
    
    memset(dist, -1, sizeof dist);
     
    int hh = 0, tt = 0;
     
    dist[x] = 0;
     
    q[tt ++ ] = x;
     
    while (hh <= tt) {
    
    
        int t = q[hh ++ ];
         
         // 三种操作依次进行,操作不论先后,先搜到的数一定是最小的转化步骤
        int u;
        for (int i = 0; i < 3; i ++ ) {
    
    		
            if (i == 0) u = t + 1;
            else if (i == 1) u = t - 1;
            else if (i == 2) u = t * 2;
         
            if (u < 0 || u > N) continue;
            if (dist[u] == -1) {
    
    
                dist[u] = dist[t] + 1;
                q[tt ++ ] = u;
            }
            if (u == k) {
    
    
                res = dist[u];
                return ;
            }
        }
    }
}
 
int main(){
    
    
    while (cin >> n >> k) {
    
    
        if (n >= k) {
    
    
            int t = (n - k) * 10;
            printf("%d:%d\n", t / 60, t % 60);
        } else {
    
    
            bfs(n);
            int t = res * 10;
            printf("%d:%d\n", t / 60, t % 60);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yl_puyu/article/details/115062756