动态规划(偏难):李白打酒加强版

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

李白打酒加强版

问题描述

话说大诗人李白, 一生好饮。幸好他从不开车。

一天, 他提着酒显, 从家里出来, 酒显中有酒 2 斗。他边走边唱:

无事街上走,提显去打酒。
逢店加一倍, 遇花喝一斗。

这一路上, 他一共遇到店 N N N 次, 遇到花 M M M 次。已知最后一次遇到的是花, 他正好把酒喝光了。

请你计算李白这一路遇到店和花的顺序, 有多少种不同的可能?

注意: 显里没酒 ( 0 斗) 时遇店是合法的, 加倍后还是没酒; 但是没酒时遇 花是不合法的。

输入格式

第一行包含两个整数 N N N M M M.

输出格式

输出一个整数表示答案。由于答案可能很大,输出模 1000000007 的结果.

样例输入

5 10

样例输出

14

样例说明

如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:

010101101000000

010110010010000

011000110010000

100010110010000

011001000110000

100011000110000

100100010110000

010110100000100

011001001000100

100011001000100

100100011000100

011010000010100

100100100010100

101000001010100

评测用例规模与约定

对于 40 40 \\% 40 的评测用例: 1 ≤ N , M ≤ 10 1 \leq N, M \leq 10 1N,M10

对于 100 100 \\% 100 的评测用例: 1 ≤ N , M ≤ 100 1 \leq N, M \leq 100 1N,M100

解题思路

由于 N , M N,M N,M最大值为100,要满足题目要求——在最后一次将酒喝完,则说明酒的上限不会超过 M M M

总共存在 N + M N+M N+M次相遇,每次相遇存在两种可能性,如果暴力枚举所有可能性,时间复杂度为 2 N + M 2^{N+M} 2N+M,无法通过。

背包问题,每件物品存在“取”和“不取”两种可能,取之后根据物品的体积和价值进行更新。
V S VS VS
相遇,最终需要经过 N N N次店, M M M次花

此处对应着相遇是否为“店”和“花”:

  • 如果是花,则花的数量 + 1 +1 +1,酒 − 1 -1 1
  • 如果是店,则店的数量 + 1 +1 +1,酒 ∗ 2 *2 2

定义 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示第 i i i次相遇,每次相遇需要维护店的数量 j j j(或花的数量 i − j i-j ij,维护其中一个即可),酒量为 k k k的方案数。

题目要求的是“遇到店 N N N 次, 遇到花 M M M 次,最后一次遇到的是花,正好把酒喝光”的方案数。也就相当于在前 N + M − 1 N+M-1 N+M1次中,遇到店 N N N次,酒量为 1 1 1的方案数( d p [ N + M − 1 ] [ N ] [ 1 ] dp[N+M-1][N][1] dp[N+M1][N][1]),因为此时最后遇到花才能恰好喝完。

d p dp dp数组的动态转移方程:

  • 初始时从家中出来有 2 2 2斗酒,可以表示为边界情况 d p [ 0 ] [ 0 ] [ 2 ] = 1 dp[0][0][2]=1 dp[0][0][2]=1
  • 如果第 i i i次相遇为花,则 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]可以由 d p [ i − 1 ] [ j ] [ k + 1 ] dp[i-1][j][k+1] dp[i1][j][k+1]转移过来,相当于前 i − 1 i-1 i1次相遇中店铺为 j j j次、酒量为 k + 1 k+1 k+1,第 i i i次为花则店铺数量不变,酒量数量减一。
  • 如果第 i i i次相遇为店,则 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]中的 k k k必须为偶数,此时从 d p [ i − 1 ] [ j − 1 ] [ k / 2 ] dp[i-1][j-1][k/2] dp[i1][j1][k/2]转移过来。

根据上述分析,可以根据 k k k的奇偶性和转移方程更新 d p dp dp数组。

实现时注意防止计算溢出。文章来源地址https://www.toymoban.com/news/detail-499794.html

AC_Code(Python3-不用滚动数组优化)

# -*- coding: utf-8 -*-
# @Author : BYW-yuwei
# @Software: python3.8.6
MOD=int(1e9+7)
dp=[[[0]*110 for i in range(110)] for j in range(210)]

n,m=map(int,input().split())
dp[0][0][2]=1
for i in range(1,n+m):
    for j in range(0,n+1):
        for k in range(0,m+1):
            if j!=0 and k%2==0:
                dp[i][j][k]=(dp[i-1][j][k+1]+dp[i-1][j-1][k//2])%MOD
            else:
                dp[i][j][k]=dp[i-1][j][k+1]
print(dp[n+m-1][n][1])

AC_Code(Python3-交替滚动数组优化)

# -*- coding: utf-8 -*-
# @Author : BYW-yuwei
# @Software: python3.8.6
MOD=int(1e9+7)
dp=[[[0]*110 for i in range(110)] for j in range(2)]
n,m=map(int,input().split())
dp[0][0][2]=1
new = 1
old = 0
for i in range(1,n+m):
    old,new = new,old
    for j in range(0,n+1):
        for k in range(0,m+1):
            if j!=0 and k%2==0:
                dp[new][j][k]=(dp[old][j][k+1]+dp[old][j-1][k//2])%MOD

            else:
                dp[new][j][k]=dp[old][j][k+1]
print(dp[new][n][1])

AC_Code(Python3-自身滚动数组优化)

# -*- coding: utf-8 -*-
# @Author : BYW-yuwei
# @Software: python3.8.6
MOD=int(1e9+7)
dp=[[0]*110 for i in range(110)]
n,m=map(int,input().split())
dp[0][2]=1
for i in range(1,n+m):
    for j in range(n,-1,-1):
        for k in range(0,m+1):
            if j!=0 and k%2==0:
                dp[j][k]=(dp[j][k+1]+dp[j-1][k//2])
            else:
                dp[j][k]=dp[j][k+1]
print(dp[n][1])

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

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

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

相关文章

  • 【算法】动态规划 ① ( 动态规划简介 | 自底向上的动态规划示例 | 自顶向下的动态规划示例 )

    动态规划 , 英文名称 Dynamic Programming , 简称 DP , 不是具体的某种算法 , 是一种算法思想 ; 具体的算法都有具体的步骤 , 如 : 二分法 , 其 有固定的解决步骤 , 先取一个中心点 , 判断解在左边还是右边 , 然后在一边再取一个中心点 , 再进行判定 , 该算法有具体的步骤 ; 动态规划

    2024年01月16日
    浏览(45)
  • 动态规划:什么是动态规划?

    动态规划(Dynamic Programming,简称Dp) 是 一种算法思想 : 将原(大)问题化解成子问题,再根据子问题的解得出原问题的解; 状态转移方程 :是一种组合关系,描述了一种原问题与子问题的组合关系 PS: 看着描述和最优子结构问题的描述一样,其实就是一样,一个是文字描述,

    2024年02月08日
    浏览(48)
  • 【算法】动态规划 ⑧ ( 动态规划特点 )

    求解类型 : 动态规划 必须是求 最值 , 可行性 , 方案数 , 三者之一 , 如果求其它内容 , 则不能使用动态规划算法 ; 求最值 : 最大值 , 最小值 等 ; 大规模问题的结果 由 小规模问题 的计算结果 取最大值 大规模问题的结果 由 小规模问题 的计算结果 取最小值 可行性 : 是否可行

    2023年04月08日
    浏览(46)
  • 动态规划入门之线性动态规划

    P1115 最大子段和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目要求求连续得一段子串使其累加和最大。 我们做动态规划首先考虑小情况,然后推而广之。 假设三个数1,-2,5. 我们先选1然后我们在-2以及-2加1里边选,我们选-1,接着我们在-1以及5里边选我们选择5 由此我们发

    2024年02月12日
    浏览(54)
  • 【动态规划专栏】--简单-- 动态规划经典题型

    目录 动态规划 动态规划思维(基础) 状态表示(最重要) 状态转移方程(最难) 初始化(细节) 填表顺序(细节) 返回值(结果) 解码方法⭐⭐ 【题目解析】   【算法原理】 C++ 算法代码 复杂度分析 【空间优化 - 滚动数组】 C++ 算法代码 复杂度分析 【DP边界、初始化

    2024年02月08日
    浏览(77)
  • 【动态规划】从入门到实践---动态规划详解

    目录 1.动态规划概念 一.定义数组元素的含义 二.找到数组元素之间的关系表达式 三.找到初始值 2.案例详解 一:爬楼梯 1.定义数组元素的含义 2.找到数组元素之间的关系表达式 3.找到初始值 案例二:最短路径 题目: 做题步骤: 1.定义数组的含义 2.找到数组元素之间的关系表

    2024年02月02日
    浏览(30)
  • 【算法 - 动态规划】原来写出动态规划如此简单!

    从本篇开始,我们就正式开始进入 动态规划 系列文章的学习。 本文先来练习两道通过 建立缓存表 优化解题过程的题目,对如何将 递归函数 修改成 动态规划 的流程有个基本的熟悉。 用最简单的想法完成题目要求的 递归 函数; 定义明确 递归函数 的功能!!! 分析是否存

    2024年02月21日
    浏览(44)
  • LeetCode练习七:动态规划上:线性动态规划

    参考《OI Wiki动态规划》、《算法通关手册》动态规划篇 1.1 动态规划简介    动态规划(Dynamic Programming) :简称 DP ,是一种通过把原问题分解为相对简单的子问题的方式而求解复杂问题的方法。 动态规划方法与分治算法类似,却又不同于分治算法。 「动态规划的核心思想

    2024年02月12日
    浏览(66)
  • 【动态规划专栏】-- 回文串问题 -- 动态规划经典题型

    目录 动态规划 动态规划思维(基础) 状态表示(最重要) 状态转移方程(最难) 初始化(细节) 填表顺序(细节) 返回值(结果) 回文子串 ⭐⭐ 【题目解析】  【算法原理】 C++ 算法代码  最长回文子串 ⭐⭐  【题目解析】  【算法原理】 C++ 算法代码   回文串分割

    2024年02月08日
    浏览(46)
  • 【动态规划专栏】-- 01 背包问题 -- 动态规划经典题型

    目录 背包问题概述 01 背包问题 01背包⭐⭐  【算法原理】 第一问 第二问 C++ 算法代码 复杂度分析 【空间优化 - 滚动数组】 C++ 算法代码 复杂度分析 分割等和子集⭐⭐ 【算法原理】  对于类01背包问题 C++ 算法代码  【空间优化 - 滚动数组】  C++ 算法代码 目标和⭐⭐ 【算

    2024年02月05日
    浏览(54)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包