牛客12576题解:动态规划解决因数跳跃问题
一、问题描述
牛客12576题要求计算从数字N跳到数字M的最少步数,每次跳跃只能跳当前数字的真因数(不包括1和自身)的距离。若无法到达则返回-1。
二、算法核心思想
采用动态规划方法:
三、完整代码实现(带注释)
#include <iostream> #include <vector> #include <climits> #include <algorithm> using namespace std; // 获取数字n的所有真因数(不包括1和n本身) vector<int> getJumps(int n) { vector<int> res; if(n <= 1) return res; // 1及以下数字没有真因数 for(int i=2; i*i<=n; ++i) { // 只需遍历到sqrt(n) if(n%i == 0) { // 找到因数 res.push_back(i); if(i != n/i) res.push_back(n/i); // 避免重复添加平方数 } } return res; } int main() { int N, M; cin >> N >> M; if(N == M) { // 特殊情况处理 cout << 0 << endl; return 0; } // 初始化DP数组,dp[i]表示到达i的最小步数 vector<int> dp(M+1, INT_MAX); dp[N] = 0; // 起点步数为0 for(int i=N; i<=M; ++i) { if(dp[i] == INT_MAX) continue; // 跳过不可达的点 vector<int> jumps = getJumps(i); // 获取当前数字的所有真因数 for(int jump : jumps) { if(i + jump > M) continue; // 跳过超出范围的情况 dp[i+jump] = min(dp[i+jump], dp[i]+1); // 状态转移 } } cout << (dp[M]==INT_MAX ? -1 : dp[M]) << endl; return 0; }
四、关键点解析
因数获取优化:
只需遍历到sqrt(n)即可找到所有因数
避免重复添加平方数的因数
动态规划初始化:
使用INT_MAX表示不可达状态
起点N的步数初始化为0
状态转移:
只处理可达的数字
检查每个因数跳跃是否超出范围
更新目标位置的最小步数
五、扩展思考
如何优化大范围(M>>N)的情况?
如果允许跳1会怎样影响算法?
如何记录具体跳跃路径?
如何处理带权重的因数跳跃?
原创内容 转载请注明出处