动态规划再学习之跳石板

题目

小易来到了一条石板路前,每块石板上从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]);
        
    }
}

温故知新, 未央书斋

你可能感兴趣的:(刷题笔记,后端相关,算法,动态规划,java)