蓝桥:保险箱(Python,动态规划)

这篇具有很好参考价值的文章主要介绍了蓝桥:保险箱(Python,动态规划)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题描述:

小蓝有一个保险箱,保险箱上共有 n 位数字。小蓝可以任意调整保险箱上的每个数字,每一次操作可以将其中一位增加 1 或减少 1。当某位原本为 9 或 0 时可能会向前(左边)进位/退位,当最高位(左边第一位)上的数字变化时向前的进位或退位忽略。

例如:
00000 的第 5 位减 1 变为 99999;
99999 的第 5 位减 1 变为 99998;
00000的第 4 位减 1 变为 99990;
97993 的第 4 位加 1 变为 98003;
99909 的第 3 位加 1 变为 00009。

保险箱上一开始有一个数字 x,小蓝希望把它变成 y,这样才能打开它,问小蓝最少需要操作的次数。

输入格式
输入的第一行包含一个整数 n。第二行包含一个 n 位整数 x。第三行包含一个 n 位整数 y。

输出格式
输出一行包含一个整数表示答案。

数据范围
对于 30% 的评测用例,1≤n≤300;
对于 60% 的评测用例,1≤n≤3000;
对于所有评测用例,1≤n≤105,x,y 中仅包含数字 0 至 9,可能有前导零。

输入样例:

5
12349
54321

输出样例:

11

思路:

又是一道省赛且没有完全AC的题,这道题刚开始压根没往动态规划方面想,结果是一个二维dp数组,其中一维表示3种状态,未进位,进位和退位状态。

下面进行分析:
分析题目发现每变动一位数字,只会影响左边的一个数。如果此时该位的数没有发生进位的话,左边的一个数就不会发生变动的;如果当前该位的数是通过加法进位的话,那么左边的一位数字就会加1;如果当前该位的数是通过减法进位的话,那么左边的一位数字就会减1。

所以发现当前一位数字是否发生变动是取决于后一位数字的变动,所以定义三种状态:

  1. 右边的数字没有发生进位
  2. 右边数字通过加法发生了进位
  3. 右边的数字通过减法发生了进位。

动规五部曲:

  1. 定义dp数组:

dp[i][0],dp[i][1],dp[i][2] 分别表示当前位没有发生进位、当前位通过加法发生进位和当前位通过减法发生进位需要操作的最少次数

  1. 递推公式:

接下来关键之处就是状态计算了,由于操作当前位并不影响右边的数,所以从右向左进行状态计算(用x表示第一个字符串当前位的数字,用y表示第二个字符串当前位的数字):

  • 当前位的数没有发生进位dp[i][0]

    1)如果右边的数操作完了之后当前位没有发生改变,那么:

    当前位不进位需要操作的次数即为:dp[i][0] = dp[i + 1][0] + abs(x - y)

    2)如果右边的数操作完了之后当前位增大了一位,那么:

    当前位不进位需要操作的次数即为:dp[i][0] = dp[i + 1][1] + abs(x + 1 - y)
    因为发生了进位,所以x要加1

    3)如果右边的数操作完了之后当前位减小了一位,那么:

    当前位不进位需要操作的次数即为:dp[i][0] = dp[i + 1][2] + abs(x - 1 - y)
    因为发生了退位,所以x要减1

    综上:dp[i][0] = min(dp[i + 1][0] + abs(x - y),dp[i + 1][1] + abs(x + 1 - y), dp[i + 1][2] + abs(x - 1 - y))

  • 当前位的数通过加法进位dp[i][1]

    1)如果右边的数操作完了之后当前位没有发生改变,那么:

    当前位通过加法进位需要操作的次数即为:dp[i][1] = dp[i + 1][0] + abs(10 - (x - y))
    如果x为2,y为8,则发生进位的情况是abs(10 -(2 - 8)) = 16,2进位到8需要加16

    2)如果右边的数操作完了之后当前位增大了一位,那么:

    当前位通过加法进位需要操作的次数即为:dp[i][1] = dp[i + 1][1] + abs(10 - (x + 1 - y))

    3)如果右边的数操作完了之后当前位减小了一位,那么:

    当前位通过加法进位需要操作的次数即为:dp[i][1] = dp[i + 1][2] + abs(10 - (x - 1 - y))

    综上:dp[i][1] = min(dp[i + 1][0] + abs(10 - (x - y)),dp[i + 1][1] + abs(10 - (x + 1 - y)), dp[i + 1][2] + abs(10 - (x - 1 - y)))

  • 当前位的数通过减法进位

    1)如果右边的数操作完了之后当前位没有发生改变,那么:

    当前位通过减法进位需要操作的次数即为:dp[i][2] = dp[i + 1][0] + abs(10 + (x - y))
    如果x为2,y为8,则发生退位的情况是abs(10 +(2 - 8)) = 4,2退位到8需要减4

    2)如果右边的数操作完了之后当前位增大了一位,那么:

    当前位通过减法进位需要操作的次数即为:dp[i][2] = dp[i + 1][1] + abs(10 + (x + 1 - y))

    3)如果右边的数操作完了之后当前位减小了一位,那么:

    当前位通过减法进位需要操作的次数即为:dp[i][2] = dp[i + 1][2] + abs(10 + (x - 1 - y))

    综上:dp[i][2] = min(dp[i + 1][0] + abs(10 + (x - y)),dp[i + 1][1] + abs(10 + (x + 1 - y)), dp[i + 1][2] + abs(10 + (x - 1 - y)))

  1. dp数组如何初始化:

因为递推公式是从右往左计算,所以

# 初始化最后一个位置的 dp 值
dp[n - 1][0] = abs(a[n - 1] - b[n - 1])  
dp[n - 1][1] = abs(10 - (a[n - 1] - b[n - 1])) 
dp[n - 1][2] = abs(10 + (a[n - 1] - b[n - 1]))  

  1. dp数组遍历顺序:

因为递推公式是从右往左计算,所以从右往左遍历

# 从倒数第二个位置开始向前遍历
for i in range(n - 2, -1, -1):
  1. 打印dp数组:

999 变到 321
上方表示状态
左侧表示数的索引值
如图:
蓝桥:保险箱(Python,动态规划),算法,python,python,动态规划,算法,蓝桥杯
最终答案为min(dp[0][0], dp[0][1], dp[0][2])

代码及详细注释:

# 读取输入的整数 n,表示数组的长度
n = int(input())
# 读取输入的两个整数列表 a 和 b,分别表示两个数组
a = list(map(int, input()))  # 将输入的字符串映射为整数列表
b = list(map(int, input()))  # 将输入的字符串映射为整数列表

# dp[i][j] 表示到达位置 i 时,使得 a[i] 的数字与 b[i] 的数字相等的最小操作次数,
# 其中 j 可能取值为 0、1、2,分别表示 a[i] - b[i] 等于 0、1、-1。
dp = [[0, 0, 0] for _ in range(n)]

# 初始化最后一个位置的 dp 值
dp[n - 1][0] = abs(a[n - 1] - b[n - 1])  
dp[n - 1][1] = abs(10 - (a[n - 1] - b[n - 1])) 
dp[n - 1][2] = abs(10 + (a[n - 1] - b[n - 1]))  

# 从倒数第二个位置开始向前遍历
for i in range(n - 2, -1, -1):
    x = a[i]
    y = b[i]

    # 计算当前位置的 dp 值
    dp[i][0] = dp[i + 1][0] + abs(x - y)  
    dp[i][0] = min(dp[i][0], dp[i + 1][1] + abs(x + 1 - y))  
    dp[i][0] = min(dp[i][0], dp[i + 1][2] + abs(x - 1 - y))  

    dp[i][1] = dp[i + 1][0] + abs(10 - (x - y))  
    dp[i][1] = min(dp[i][1], dp[i + 1][1] + abs(10 - (x + 1 - y)))  
    dp[i][1] = min(dp[i][1], dp[i + 1][2] + abs(10 - (x - 1 - y)))  

    dp[i][2] = dp[i + 1][0] + abs(10 + (x - y))  
    dp[i][2] = min(dp[i][2], dp[i + 1][1] + abs(10 + (x + 1 - y)))  
    dp[i][2] = min(dp[i][2], dp[i + 1][2] + abs(10 + (x - 1 - y)))  

# 输出最小操作次数
print(min(dp[0][0], dp[0][1], dp[0][2]))

总结:

省赛10分的题,结果写了半天ac了25%,拿了3分,之后看到类似的题分析到状态就要考虑是否能用dp来解决。文章来源地址https://www.toymoban.com/news/detail-845223.html

到了这里,关于蓝桥:保险箱(Python,动态规划)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 用python实现动态规划算法

    动态规划(Dynamic Programming,DP)是一种常用的算法思想,通常用于解决具有重叠子问题和最优子结构性质的问题。动态规划算法通常是将问题分解为子问题,先解决子问题,再由子问题的解推导出原问题的解。 动态规划算法的基本步骤如下: 确定状态:定义状态变量,表示

    2024年02月07日
    浏览(34)
  • 蓝桥杯算法全集之多重背包问题I(动态规划算法)

    有 N 种物品和一个容量是 V 的背包。 第 i 种物品最多有 s i 件,每件体积是 v i ,价值是 w i 。 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。 用下面这个图来分别动态规划的四个经典背包问题 定义状态的含义(这一步需要

    2023年04月08日
    浏览(38)
  • python算法与数据结构---动态规划

    记不住过去的人,注定要重蹈覆辙。 对于一个模型为n的问题,将其分解为k个规模较小的子问题(阶段),按顺序求解子问题,前一子问题的解,为后一子问题提供有用的信息。在求解任一子问题时,通过决策求得局部最优解,依次解决各子问题。最后通过简单的判断,得到

    2024年02月20日
    浏览(65)
  • Leetcode题解-算法-动态规划(python版)

    1.1 爬楼梯 70. 爬楼梯(Easy) 走n阶楼梯的方法有两种,1、先走 1 级台阶,再走 n-1 级台阶;2、先走 2 级台阶,再走 n-2 级台阶 f(n) = f(n-1) + f(n-2) 1.2 强盗抢劫 198. 打家劫舍(Medium) 每个房间财产为 nums[0]……nums[n-1]。 假设 0 至 x 间房获得的最大财产为 f(x)。 f(x) = max(f(x-1),f(x-2)+nums[

    2024年02月03日
    浏览(47)
  • 【Python算法】实验12-动态规划与背包问题

    目录 实验内容 1.数塔dp -A 2.骨牌铺方格 3.一只小蜜蜂

    2024年02月15日
    浏览(40)
  • 【Python算法】实验8-动态规划与背包问题

    目录 实验内容 1.数塔dp -A 2.骨牌铺方格 3.一只小蜜蜂

    2023年04月19日
    浏览(66)
  • 动态规划的算法题以及其python实现

    动态规划(Dynamic Programming)是一种常用的算法设计技术,用于解决具有最优子结构性质和重叠子问题的问题。它通过将原问题分解为若干个子问题,并先求解子问题的最优解,然后利用子问题的最优解构建原问题的最优解。 动态规划算法通常包括以下几个 关键步骤 : 定义

    2024年02月07日
    浏览(32)
  • 算法练习Day30 (Leetcode/Python-动态规划)

    62. Unique Paths There is a robot on an  m x n  grid. The robot is initially located at the  top-left corner  (i.e.,  grid[0][0] ). The robot tries to move to the  bottom-right corner  (i.e.,  grid[m - 1][n - 1] ). The robot can only move either down or right at any point in time. Given the two integers  m  and  n , return  the number of possible

    2024年01月20日
    浏览(41)
  • Python 算法基础篇:背包问题的动态规划解法

    背包问题是计算机科学中一个重要的组合优化问题,动态规划是解决该问题的高效算法技术。本篇博客将重点介绍背包问题的动态规划解法,包括状

    2024年02月16日
    浏览(39)
  • python数据结构与算法-动态规划(最长公共子序列)

    一个序列的子序列是在该序列中删去若干元素后得 到的序列。 例如:\\\"ABCD”和“BDF”都是“ABCDEFG”的子序列。 最长公共子序列(LCS) 问题: 给定两个序列X和Y,求X和Y长度最大的公共子字列。 例:X=\\\"ABBCBDE”Y=\\\"DBBCDB”LCS(XY)=\\\"BBCD\\\" 应用场景:字符串相似度比对 (1)问题思考 思考: 暴

    2024年02月08日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包