原题链接
https://pintia.cn/problem-sets/994805148990160896/exam/problems/1697152161245261825?type=7&page=0
题目大意
给定三个整数
A
,
B
,
N
A,B,N
A,B,N,目标是从
A
A
A开始变成
B
B
B,其中每一步从以下三种变化方法中选择一个:(现在的数字是
X
X
X)
(
1
)
X
=
X
+
1
(1) X = X+1
(1)X=X+1
(
2
)
X
=
X
−
1
(2)X = X-1
(2)X=X−1
(
3
)
X
=
X
×
n
(3)X = X\times n
(3)X=X×n
求最小的变化次数。
数据范围
−
1
0
5
<
=
A
,
B
<
=
1
0
5
-10^5 <= A,B <= 10^5
−105<=A,B<=105
1
<
N
<
10
1 < N < 10
1<N<10
题解
非常简单的BFS题,利用一个队列进行BFS,用一个数组记录步骤数。从
A
A
A出发,起始时将
A
A
A压入队列。假设某一时刻队列头的元素是
X
X
X,达到
X
X
X所需要的步骤数是
i
i
i,下一步可以到达的数字是
X
+
1
,
X
−
1
,
X
×
N
X+1,X-1,X\times N
X+1,X−1,X×N,这三个数字如果之前已经访问过,则不再压入队列,否则压入队列且步骤数即为
i
+
1
i+1
i+1,持续进行类似操作直到选择到
B
B
B即可。
唯一需要注意的是,需要卡住数字的上下界,否则会有数组越界或超时的问题。当目前的
X
X
X足够大的时候,就没有必要继续向上乘。我们也不需要严谨地证明这个上界是多少,我做题的时候这个
X
X
X的范围以
1
0
5
10^5
105向上下各偏差
200000
200000
200000为界限都足以通过本题。由于B可能有负数,整体加一个偏移量即可。
AC代码
#include <bits/stdc++.h>
using namespace std;
int bias = 300000;
int main()
{
int t;
cin >> t;
while(t--){
int f[600050] = {0};
memset(f,0x3f,sizeof f);
int a,b,n;
cin >> a >> b >> n;
f[bias+a] = 0;
queue<int> q;
q.push(bias + a);
while(q.front() != bias + b){
int u = q.front();
if(u<500000) {
if(f[u+1] > f[u] + 1){
f[u+1] = f[u] + 1;
q.push(u+1);
}
}
if(u>100000) {
if(f[u-1] > f[u] + 1){
f[u-1] = f[u] + 1;
q.push(u-1);
}
}
u -= bias;
if(u*n + bias >= 100000 && u*n + bias <= 500000){
if(f[u*n+bias] > f[u+bias] + 1){
f[u*n+bias] = f[u+bias] + 1;
q.push(u*n + bias);
}
}
q.pop();
}
cout << f[b+bias] << endl;
}
}