小易来到了一条石板路前,每块石板上从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号石板
动态规划重点就是状态的递进式变化。
本题目中需要求最少跳跃次数,第一反应是贪心算法,但是贪心算法的局限性导致未必能得到最优解。所以考虑动态规划。
我们可以对 N N N到 M M M期间的每一个数字求 N N N 到 N + k ( k ∈ ( N , M ) N+k(k \in (N,M) N+k(k∈(N,M)的最少跳跃次数。
创建一个数组 s t e p [ i ] step[i] step[i],初始化值为 I n t e g e r . M A X _ V A L U E Integer.MAX\_VALUE Integer.MAX_VALUE,从序号 N N N开始遍历,若 s t e p [ i ] step[i] step[i]为初始值,表示该点不可达,继续循环。若该点可达,求解约数,进行动态规划向前递推。
s t e p [ i + j ] = M a t h . m i n ( s t e p [ i ] + 1 , s t e p [ i + j ] ) s t e p [ N ] = 0 \begin{aligned} step[i+j] &= Math.min(step[i]+1,step[i+j])\\ step[N] &= 0 \end{aligned} step[i+j]step[N]=Math.min(step[i]+1,step[i+j])=0
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
//输入的两个数字
int N = sc.nextInt();
int M = sc.nextInt();
//状态数组
int[] step = new int[M+1];
//填充最大值
Arrays.fill(step,Integer.MAX_VALUE);
//设置开始值为0,让程序开始
step[N] = 0;
for(int i =N; i<=M;i++){
//不可达点跳过
if(step[i] == Integer.MAX_VALUE)continue;
//求约数
for(int j=2; (j*j)<=i;j++){
if(i%j==0){
//小的约数
if(i+j <= M)
step[i+j] = Math.min(step[i]+1,step[i+j]);
//与J对应的大的约数
if(i+(i/j) <= M)
step[i+(i/j)] = Math.min(step[i]+1,step[i+(i/j)]);
}
}
}
//最终仍然不可达,设置值为-1
if(step[M] == Integer.MAX_VALUE)
step[M] = -1;
//输出
System.out.println(step[M]);
}
}
温故知新, 未央书斋