小易来到了一条石板路前,每块石板上从1挨着编号为:1、2、3.......
这条石板路要根据特殊的规则才能前进:对于小易当前所在的编号为K的 石板,小易单次只能往前跳K的一个约数(不含1和K)步,即跳到K+X(X为K的一个非1和本身的约数)的位置。 小易当前处在编号为N的石板,他想跳到编号恰好为M的石板去,小易想知道最少需要跳跃几次可以到达。
例如:
N = 4,M = 24:
4->6->8->12->18->24
于是小易最少需要跳跃5次,就可以从4号石板跳到24号石板

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

//求出n的所有非1和n的约数
/*
注意这里求约数的方法:以n的平方根为界限。先找出一个能整除的数,将除数放入约数数组中。
若判断除数不是他的平方根,再将对应的商放入数组中。
例如:24/2=12,此时n的界限为根号24,访问不到12,所以可以直接将除数与商放入数组中。
9/3=3,此时n的界限为3,只能将一个3放入数组中。
而且这样做了之后,约数数组中的数不是从大到小排列的,所以在下面得注意。
*/
void CommonDivision(int n, vector<int>& cd)
{
    for (int i = 2; i <= sqrt(n); i++)
    {
        if (n % i == 0)
        {
            cd.push_back(i);
            if (n / i != i)
                cd.push_back(n / i);
        }
    }
    //加上sort函数使其有序,下面判断越界的时候就不用全部遍历了,只用遍历不超过范围的前一部分即可
    sort(cd.begin(),cd.end());
}

/*
用矩阵dist[]表示n--m这一路每个点的可达性信息,存储到该点的最小距离;
若x从未被访问过,则dist[x]等于前一步的最小步数加1;若x被访问过,则dist[x]等于原值与前一步加1的最小值。
所以动态方程为dist[cd[j] + i] = min(dist[cd[j] + i], dist[i] + 1);
i为石板编号,j为i的约数
*/
int main()
{
    int n, m;
    cin >> n >> m;
    if (n == m)
    {
        cout << '0' << endl;
        return 0;
    }
    //建立表示步数的数组,范围0-m,初始化为0
    vector<int> dist(m + 1, 0);
    //循环求出从起点n到[n,m]范围内点的最小步数
    for (int d = n; d < m; d++)
    {
        //0表示这个点从前面的点不可到
        if (dist[d] == 0 && d != n)
            continue;

        //求出d的约数
        vector<int> cd;
        CommonDivision(d, cd);

        //对于d的每一个约数,逐个访问并更新从n到达他们的最小步数
        for (int i = 0; i < cd.size(); i++)
        {
            //要保证d+约数在m之内,否则会越界
            if (d + cd[i] <= m)
            {
                //若下一个点没有被访问过,则直接更新
                if (dist[d + cd[i]] == 0)
                    dist[d + cd[i]] = dist[d] + 1;
                //若下一个点已经被访问过,则取两者最小值
                else
                    dist[d + cd[i]] = min(dist[d + cd[i]], dist[d] + 1);
            }
            else
                break;

        }
    }
    if (dist[m] > 0)
        cout << dist[m] << endl;
    else
        cout << "-1" << endl;
    return 0;
}