题目描述
红红今天中午想去市中心吃饭,他决定坐公交车去。但是去公交车的时候红红决定练习一下空间魔法,穿梭时空
现在红红到公交车的路是一条直线,然后他可以通过三种方式移动:
-
向前走一个位置
-
向后走一个位置
-
空间移动,将自己的位置从
x
移动到2 * x
三种移动方式都需要 10 s
但是红红希望能尽量减少体力的消耗, 所以他希望能以最短的时间到达公交车站
输入
有多组测试样例
每组测试样例包括一个 n
和 k
( 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;
}