2024/4/1打卡保险箱(十四届蓝桥杯)—— 动态规划,贪心

目录

题目

动态规划思路

代码

贪心思路


题目

动态规划思路

一开始,通过题意可以发现,修改左边位的值不会影响右边的值,因此我们可以考虑从最右边开始向前枚举,进行修改。

**(错误思想开始)**一开始,我想到用线性Dp。用f[i]表示,从第n位开始,向前 i 位成为y的所有方案。

注:不进位不退位就是直接在0~9之内相加减;进位就是向上加,超过10需要进位;退位就是向下减,减到0需要下一位退位。

因此:状态计算分为三种:

1、

2、 只考虑两种情况,一是不进位也不退位,二是退位(因为进位必会在还没加到10时就到y)

  • (这里还要考虑退位的问题)

3、 也考虑两种情况,一是不进位也不退位,二是进位(因为退位必会在还没减到0时就到y)

  • (这里还要考虑进位的问题)

然后用一个数组 来记录每次的进位还是退位。

**(问题)**但是,写完之后发现,好像写成了贪心的方式,每次都只取当前所有可能的最优解,然后进行计算。我们是否能保证每一位都选最优解然后求解最终的最优解,能否保证当前这位的最优解是能从上一位最优解传递过来? 其二一个问题,如果,不能保证是不进位不退位还是进位或者退位是最优解。

太菜了只能说还是,参考大佬的文章AcWing 5408. 保险箱(状态机DP) - AcWing

(正确思想)使用状态机DP。因为每一种方式(即不进位不退位,进位向上加,退位)都可能是最优解,每一位的最优解都需要从这三种状态中求解当前为这三种状态的最优解。意思就是,这一位选择不进位不退位可以从上一位的不进位不退位,进位,退位三种状态中传递过来。不是直接去三种最优就传递给下一位!

**(正片开始)**分析:

使用 来进行状态表示

  • 表示当前这位不进位不退位 ,可以从前三种状态 转移过来。具体 ,取min。

+1 是因为上一位进位,x[i]+1;-1 是因为上一位退位,x[i]-1。

  • 表示当前这位进位 ,同样可从前一位的三种状态转移过来。具体 ,取min。

-1 是因为上一位进位,这一位可以少加一个1;+1是因为上一位退位,这一位要多加一个1。

  • 表示当前这位退 ,同样可从前一位的三种状态转移过来。具体 ,取min。

+1 是因为上一位进位,这一位要多减一个1;-1是因为上一位退位,这一位可以少减一个1。

代码

很多细节,注释中有解释

java 复制代码
import java.io.*;
import java.util.*;

class Main{
    static int N = 100010;
    static int n;
    static int[] x = new int[N];
    static int[] y = new int[N];
    static int[][] f = new int[N][3]; //0 表示既不进位也不退位, 1 表示进位(即向上加),2 表示退位(即向下减)
    static int[] e = new int[N]; 
    public static void main(String[] args) throws IOException{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(in.readLine());
        String x1 = in.readLine();
        String y1 = in.readLine();
        for(int i=0;i<n;i++){
            x[i] = Integer.parseInt(String.valueOf(x1.charAt(i)));
            y[i] = Integer.parseInt(String.valueOf(y1.charAt(i)));
        }
        
        f[n-1][0] = Math.abs(x[n-1]-y[n-1]);
        f[n-1][1] = 10-x[n-1]+y[n-1];
        f[n-1][2] = 10-y[n-1]+x[n-1];
        for(int i=n-2;i>=0;i--){
            // 不进位也不退位
            f[i][0] = f[i+1][0]+Math.abs(x[i]-y[i]);
            f[i][0] = Math.min(f[i][0],f[i+1][1]+Math.abs(x[i]-y[i]+1)); // 这里+1,是因为上一位进位了,那么x[i]就会变成x[i]+1
            f[i][0] = Math.min(f[i][0],f[i+1][2]+Math.abs(x[i]-y[i]-1)); // 这里-1,是因为上一位退位了,那么x[i]就会变成x[i]-1
            
            // 进位,向上加
            f[i][1] = f[i+1][0]+Math.abs(10-x[i]+y[i]);
            f[i][1] = Math.min(f[i][1],f[i+1][1]+10-x[i]+y[i]-1); // 如果上一位进位,这一位向上加就可以少加一次
            f[i][1] = Math.min(f[i][1],f[i+1][2]+10-x[i]+y[i]+1); // 如果上一位退位,这一位向上加就要多加一次
            
            // 退位,向下减
            f[i][2] = f[i+1][0]+Math.abs(10-y[i]+x[i]);
            f[i][2] = Math.min(f[i][2],f[i+1][1]+10-y[i]+x[i]+1); // 如果上一位进位,这一位向下减就要多减一次
            f[i][2] = Math.min(f[i][2],f[i+1][2]+10-y[i]+x[i]-1); // 如果上一位退位,这一位向下减就可以少减一次
        }
        int res = Math.min(f[0][0],f[0][1]);
        res = Math.min(res,f[0][2]);
        System.out.println(res);
    }
}



贪心思路

然后我叒参考了一篇大佬的解析,使用贪心AcWing 5408. 保险箱-贪心(+势能分析) - AcWing

相关推荐
我是咸鱼不闲呀11 分钟前
力扣Hot100系列19(Java)——[动态规划]总结(上)(爬楼梯,杨辉三角,打家劫舍,完全平方数,零钱兑换)
java·leetcode·动态规划
qq74223498415 分钟前
APS系统与OR-Tools完全指南:智能排产与优化算法实战解析
人工智能·算法·工业·aps·排程
A尘埃41 分钟前
超市购物篮关联分析与货架优化(Apriori算法)
算法
.小墨迹1 小时前
apollo学习之借道超车的速度规划
linux·c++·学习·算法·ubuntu
不穿格子的程序员1 小时前
从零开始刷算法——贪心篇1:跳跃游戏1 + 跳跃游戏2
算法·游戏·贪心
大江东去浪淘尽千古风流人物1 小时前
【SLAM新范式】几何主导=》几何+学习+语义+高效表示的融合
深度学习·算法·slam
重生之我是Java开发战士1 小时前
【优选算法】模拟算法:替换所有的问号,提莫攻击,N字形变换,外观数列,数青蛙
算法
仟濹1 小时前
算法打卡 day1 (2026-02-06 周四) | 算法: DFS | 1_卡码网98 可达路径 | 2_力扣797_所有可能的路径
算法·leetcode·深度优先
yang)1 小时前
欠采样时的相位倒置问题
算法
历程里程碑1 小时前
Linux20 : IO
linux·c语言·开发语言·数据结构·c++·算法