整数转换最小步数问题:BFS解法超时,求优化方案
问题描述
给定整数a、b、c,需通过以下三种可任意顺序、任意次数执行的操作将a转换为b:
- 将a乘以c
- 将a减2
- 将a减1
要求找出并输出转换所需的最小步数。
约束条件:
- 1 ≤ t ≤ 10^4
- 0 ≤ a, b, c ≤ 10^9
输入输出格式:
- 输入:第一行是测试用例数t,接下来t行每行包含三个空格分隔的整数a、b、c
- 输出:每行输出对应测试用例的最小步数
示例输入:
2 3 10 2 11 6 2
示例输出:
3 3
问题分析与优化方案
你的BFS解法超时的核心原因是:当a、b、c达到1e9量级时,正向搜索会产生指数级增长的状态,导致遍历次数过多,同时unordered_set的内存开销和查找效率也会成为瓶颈。此外,代码中还存在整数溢出、错误的边界判断(如a < b && c <=1时返回0)以及调试输出拖慢速度的问题。
正确的思路是反向推导:从b出发反推到a,这样可以避免处理过大的中间值,将时间复杂度降到O(log_c b),完全适配1e4的测试用例规模。
反向操作对应关系:
- 原操作「乘c」→ 反向操作「若当前数能被c整除,则除以c」(步数+1)
- 原操作「减2」→ 反向操作「加2」(步数+1)
- 原操作「减1」→ 反向操作「加1」(步数+1)
具体步骤:
- 若
a == b,直接返回0 - 若
a > b,只需用减法,最小步数为向上取整(a-b)/2,即(a - b + 1) / 2 - 若
a < b且c <=1,无法通过乘法增大a,无法到达b,返回-1 - 若
a < b且c >1,从b开始反向推导:- 当当前数大于a时,若无法被c整除,先补到能被c整除(用最少的加1/加2操作)
- 若除以c后小于a,直接计算从a到当前数的步数,终止循环
- 否则除以c,步数+1
- 最后计算从剩余值到a的步数
优化后的C++代码
#include <iostream> using namespace std; typedef long long ll; ll minimumSteps(ll a, ll b, ll c) { if (a == b) return 0; if (a > b) { return (a - b + 1) / 2; } // a < b 且 c <=1 时无法增大a,无法到达b if (c <= 1) { return -1; } ll curr = b; ll steps = 0; while (curr > a) { // 补到能被c整除 if (curr % c != 0) { ll d = c - (curr % c); steps += (d + 1) / 2; curr += d; } // 避免除以c后小于a,直接计算从a到curr的步数 if (curr / c < a) { steps += (curr - a + 1) / 2; curr = a; break; } curr /= c; steps++; } // 处理剩余从curr到a的步数 steps += (a - curr + 1) / 2; return steps; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { ll a, b, c; cin >> a >> b >> c; cout << minimumSteps(a, b, c) << "\n"; } return 0; }
代码说明
- 使用
long long避免整数溢出(当处理1e9量级的数时,乘法/加法容易超出int范围) - 关闭同步流
ios::sync_with_stdio(false);和解绑cintie(nullptr);提升输入输出速度 - 反向推导大幅减少了计算次数,每个测试用例仅需O(log_c b)次循环
- 正确处理了所有边界情况,包括无法转换的场景
内容的提问来源于stack exchange,提问作者Om Londhe
相关产品推荐
相关产品推荐

