动态规划的万能公式(三类题型)

news2024/11/16 12:35:48

本文主要介绍如何用Python解决动态规划的问题,在动态规划问题中,最主要的是找到问题的dp,即找到状态转移函数,当你找到了该问题的状态转移函数,你就成功了一半,下面我将介绍三类最主要的题型,对于这三类题型,分别有着不同的解题公式。

目录

一、斐波那契式

通项公式:f(n)=f(n-1)+f(n-2) 

举例说明

爬楼梯 

骨牌铺方格 

一只小蜜蜂

二、背包问题

通项公式:f(i,j)=max(f(i-1,j),f(i-1(或i),j-w(i))+v(i)) 

举例说明 

0-1背包问题 

完全背包问题 

矿工问题

三、最长递增子列

通项公式:f(i,j)=max(f(i),f(j)+1)

举例说明 

最长递增子序列

最少拦截系统 


 

 

一、斐波那契式

这一类题型基本都有一定的规律,一般思维是从最后往前推,找出状态转移函数。 

通项公式:f(n)=f(n-1)+f(n-2) 

def f(n):
    if n<?:       #首先需要单独考虑几个特别的值
        return
    ……
    if n==t:
        return
    a,b=?,?     
    for i in range(t,n):
        sums=a+b  #该句其实就是动态规划(根据具体情况而改变),表示当前的方法数实际上是前面两个方法数之和
        a=b
        b=sums
    return sums

举例说明

爬楼梯 

【问题描述】

假设小明住在二楼,每次回家都需要经过一个有n层台阶的楼梯。

小明每次可以选择一步走一级台阶或者一步走两级台阶。

请计算一下小明从楼下到家一共有多少种走法?

【输入形式】

整数n,表示一共有几层台阶

【输出形式】

一行,表示一共有多少种走法

【样例输入】

10

【样例输出】

89

def Climb(n):     #定义的爬楼梯函数
    if n<1:       #判断是否合法,台阶不合法,返回0
        return 0 
    if n==1:      #当只有一层台阶时,一种走法
        return 1
    if n==2:      #当有两层台阶时,两种走法
        return 2
    a,b=1,2       #当台阶数大于3时,我们发现走法数呈斐波那契排列
    sums=0        #即每一层台阶的走法数等于前两层台阶走法数的和
    for i in range(2,n):     #这是为什么呢,因为我们知道,每次只能走1步或者2步
        sums=a+b      #倒推一下,我们如何能到达第n级台阶呢,有两种方法
        a=b           #一种是在第9层台阶再走1步,另一种是在第8层台阶再走2步
        b=sums        #而到达第9层也是两种方法,在第7层走两步或在第8层走一步
    return sums      #同理所以我们只需要n层前两层走的步数和即可
n=int(input())        #而前两层又等于前前两层……,是个斐波那契数列
print(Climb(n))

骨牌铺方格 

【问题描述】

在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数. 例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图:

【输入形式】

输入数据由多行组成,每行包含一个整数n,表示该测试实例的长方形方格的规格是2×n (0<n<=50)。

【输出形式】

对于每个测试实例,请输出铺放方案的总数,每个实例的输出占一行。

【样例输入】

1

3

2

【样例输出】

1

3

2

while(1):
    def get(n):
        if n<1:
            return 0
        if n==1:
            return 1
        if n==2:
            return 2
        a,b=1,2
        for i in range(2,n):
            sums=a+b
            a=b
            b=sums
        return sums
    n=int(input())
    print(get(n))

一只小蜜蜂

【问题描述】

有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。 其中,蜂房的结构如下所示。

4546d5f77e99418694ea5fa45212f10d.jpeg

 

【输入形式】

输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<a<b<50)。

【输出形式】

对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。

【样例输入】

2

1 2

3 6

【样例输出】

1

3

def methods(a,b):
    t=b-a
    if t<1:
        return 0
    if t==1:
        return 1
    if t==2:
        return 2
    a,b=1,2
    for i in range(2,t):
        sums=a+b
        a=b
        b=sums
    return sums
N=int(input())
for i in range(N):
    a,b=map(int,input().split())
    print(methods(a,b))

二、背包问题

这类问题细分为0-1背包问题和完全背包问题,具体差别就在于物品是否有无穷个。

通项公式:f(i,j)=max(f(i-1,j),f(i-1(或i),j-w(i))+v(i)) 

def f(n,m,v,w):
    dp=[[0 for i in range(m+1)] for j in range(n+1)]
    for i in range(1,n+1):
        for j in range(1,m+1):
            if j<v[i-1]:
                dp[i][j]=dp[i-1][j]
            else:         #0-1背包(完全背包)
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i-1]](或dp[i][j-w[i-1]])+v[i-1])
    return dp

举例说明 

0-1背包问题 

假设有一个承重力量为C的背包。现有n件物品,质量分别为w1,w2,……,wn,价值分别为v1,v2,……vn,求让背包里装入的物品具有最大价值总和的物品子集。

【问题描述】

假设周末学校要组织跳蚤市场,某学生准备了电子词典、篮球、网球拍和考研书4件物品进行交易,要用自己的书包把这些物品带到学校。各个物品的质量w和价值v如表所示,该学生书包的最大承重量C=8。我们要解决的问题是帮助该同学找到最合理的搭配方案,使他能用书包带到学校的物品价值最大。

电子词典 篮球 网球拍 单词书

2 4 5 3

5 4 6 2

【输入样例】

【输出样例】

一行,表示最优方案的物品

【样例输入】

【样例输出】

1 3

n=4
c=8
w=[2,4,5,3]
v=[5,4,6,2]
def bag(n,c,w,v):
    results=[[0 for i in range(c+1)] for j in range(n+1)]
    for i in range(1,n+1):
        for j in range(1,c+1):
            if j<w[i-1]:
                results[i][j]=results[i-1][j]
            else:  #在这里最多只能取一个物品,所以取了当前物品后需要返回上一层
                results[i][j]=max(results[i-1][j],results[i-1][j-w[i-1]]+v[i-1])
    return results
res=bag(n,c,w,v)
def rec(n,c,w,res):
    x=[0 for i in range(n+1)]
    j=c
    i=n
    while i>=0:
        if res[i][j]>res[i-1][j]:
            x[i]=1
            j=j-w[i]
        i=i-1
    for i in range(1+n):
        if x[i]==1:
            print(i,end=' ')
rec(n,c,w,res)

完全背包问题 

【问题描述】

对于吃货来说,过年最幸福的事就是吃了,没有之一!

但是对于女生来说,卡路里(热量)是天敌啊!

资深美女湫湫深谙“胖来如山倒,胖去如抽丝”的道理,所以她希望你能帮忙制定一个食谱,能使她吃得开心的同时,不会制造太多的天敌。

当然,为了方便你制作食谱,湫湫给了你每日食物清单,上面描述了当天她想吃的每种食物能带给她的幸福程度,以及会增加的卡路里量。

【输入形式】

输入包含多组测试用例。

每组数据以一个整数n开始,表示每天的食物清单有n种食物。

接下来n行,每行两个整数a和b,其中a表示这种食物可以带给湫湫的幸福值(数值越大,越幸福),b表示湫湫吃这种食物会吸收的卡路里量。

最后是一个整数m,表示湫湫一天吸收的卡路里不能超过m。

【输出形式】

对每份清单,输出一个整数,即满足卡路里吸收量的同时,湫湫可获得的最大幸福值。

【样例输入】

3

3 3

7 7

9 9

10

5

1 1

5 3

10 3

6 8

7 5

6

【样例输出】

10

20

while(1):
    def bag(n,m,Happiness,Calorie):
        results=[[0 for i in range(m+1)] for j in range(n+1)]
        for i in range(1,n+1):
            for j in range(1,m+1):
                if j<Calorie[i-1]:
                    results[i][j]=results[i-1][j]
                else:     #因为物品无穷个,所有选完后需要在当前层继续选,不用返回上一层
                    results[i][j]=max(results[i-1][j],results[i][j-Calorie[i-1]]+Happiness[i-1])
        return results
    n=int(input())
    Happiness=[]
    Calorie=[]
    for i in range(n):
        a,b=map(int,input().split())
        Happiness.append(a)
        Calorie.append(b)
    m=int(input())
    res=bag(n,m,Happiness,Calorie)
    print(res[-1][-1])

矿工问题

【问题描述】

假设某地区有5座钻石矿,每座钻石矿的钻石储量不同,根据挖矿难度,需要参与挖掘的工人数量也不同。假设能够参与挖矿工人的总数是10人,且每座钻石矿要么全挖,要么不挖,不能只派出一部分人挖取一部分矿产。要求用程序求解出,要想得到尽可能多的钻石,应该选择挖取哪几座矿产?

矿产编号 钻石储量 所需工人数量

1 400 5

2 500 5

3 200 3

4 300 4

5 350 3

【输入形式】

【输出形式】

一行,表示获得的最大矿产数

【样例输入】

【样例输出】

900

G=[400,500,200,300,350]
L=[5,5,3,4,3]
def goldMine(n,m,G,L):
    dp=[[0 for i in range(m+1)] for j in range(n+1)]
    for i in range(1,n+1):
        for j in range(1,m+1):
            if j<L[i-1]:
                dp[i][j]=dp[i-1][j]
            else:
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-L[i-1]]+G[i-1])
    return dp
lst=goldMine(5,10,G,L)
print(lst[-1][-1])

三、最长递增子列

这个式子主要是求最长递增子列的长度,而事实上我们还需要求得最长递增子列的元素。 

通项公式:f(i,j)=max(f(i),f(j)+1)

def f(arr):
    dp=[1]*len(arr)
    for i in range(len(arr)):
        for j in range(i):
            if arr[j]<arr[i]:          
                dp[i]=max(dp[i],dp[j]+1)      #状态转移函数
    return dp

举例说明 

最长递增子序列

【问题描述】

最长递增子序列问题即给定一个序列,求解其中最长的递增子序列的长度问题。

先给定序列A{3,1,4,5,9,2,6,5,0},求其最长递增子序列。

【输入样例】

一行,输入A

【输出样例】

一行,最长递增子序列

【样例输入】

3 1 4 5 9 2 6 5 0

【样例输出】

1 4 5 9

def getdp1(arr):    #求得最长递增子列的长度
    n=len(arr)
    dp=[0 for i in range(n)]
    for i in range(n):
        dp[i]=1
        for j in range(i):
            if arr[i]>arr[j]:
                dp[i]=max(dp[i],dp[j]+1)     #动态规划
    return dp
def generateLST(arr):     #求得最长递增子列的元素
    dp=getdp1(arr)
    n=max(dp)
    index=dp.index(n)
    lis=[0]*n
    n-=1
    lis[n]=arr[index]
    for i in range(index-1,-1,-1):
        if arr[i]<arr[index] and dp[i]==dp[index]-1:
            n-=1
            lis[n]=arr[i]
            index=i
    return lis
arr=[3,1,4,5,9,2,6,5,0]
for i in generateLST(arr):
    print(i,end=' ')

最少拦截系统 

【问题描述】

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.

【输入形式】

输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)

【输出形式】

对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.

【样例输入】

8 389 207 155 300 299 170 158 65

【样例输出】

2

def getdp(arr):                          #得到每个元素的最长递减序列
    n=len(arr)                         
    dp=[1]*n                             #每个元素的最长递减序列初始化都是1
    for i in range(n):                   
        for j in range(i):                     
            if arr[i]<arr[j]:            #从第一个元素一直到当前元素,找比当前元素大的
                dp[i]=max(dp[i],dp[j]+1)   #找到后,动态规划,找到最大的长度
    return dp                            #最后得到的是每个元素的最大递减子序列长度
def generateLST(arr):                    #获取最大递减子序列的元素
    dp=getdp(arr)                       
    n=max(dp)
    index=dp.index(n)
    lst=[0]*n                            #初始化结果列表
    n-=1
    lst[n]=arr[index]                    #最后一个值容易得到
    for i in range(index-1,-1,-1):      #从后往前遍历
        #当找到比当前元素大并且该元素的最大递减子序列长度比当前元素的最大递减子序列长度小1时
        if arr[i]>arr[index] and dp[i]==dp[index]-1:      
            lst[n]=arr[i]    #该元素就是一个结果,加入结果列表中
            index=i          #更新当前元素
            n-=1             
    return lst
while(1):
    arr=[int(i) for i in input().split()]   
    arr.pop(0)
    sums=0
    while arr:
        sums+=1
        res=generateLST(arr)       #每次找到最大递减子序列,这些都可以用一个导弹拦截系统拦截
        for i in res:             #拦截完就从列表中删除,一直删除直到列表中没有导弹了,得到的就是最小的拦截系统数
            arr.remove(i)
    print(sums)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/186543.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FreeRTOS事件实验

前面章节我们学习了如何使用信号量来实现同步&#xff0c;但是使用信号量来同步的 话任务只能与单个的任务进行同步。有时候某个任务可能会需要与多个任务进行 同步&#xff0c;此时信号量就无能为力。FreeRTOS 为此提供了一个可选的解决方法&#xff0c;那 就是事件标志组。本…

TypeScript基础使用

TypeScript介绍&#xff1a; TypeScript 是 JavaScript 的一个超集 它的第一个版本发布于 2012 年 10 月&#xff0c;vue3和react也完全支持typescrpt 为什么选择 TypeScript&#xff1a; 类型系统实际上是最好的文档&#xff0c;大部分的函数看看类型的定义就可以知道如何使…

高性能SQL-数据库性能优化

数据库性能优化涉及各个方面,本文就总多个角度介绍一下数据库性能优化的方法 1.表设计 聚集索引 一个表只能有一个聚集索引&#xff0c;数据在磁盘上的排练顺序与聚集索引一致&#xff0c;根据业务仔细设定聚集索引&#xff0c;值递增的不可修改的字段才能设置聚集索引&…

海康摄像头Linux开发

官方sdk下载 https://open.hikvision.com 点击下载就行了 Ubuntu摄像头抓拍测试 我们使用Linux64 纯净版测试 接好海康摄像头&#xff0c;通电&#xff0c;并设置号ip和用户名、密码。如果有现成的&#xff0c;可以去查一下就知道了 先把设备下载的文件解压并放到Ubuntu下面…

redis的渐进式rehash机制

简述 在redis的字典&#xff08;dict.h&#xff09;实现中&#xff0c;当哈希表保存的键值对太多或者太少时&#xff0c;会触发扩展/收缩&#xff1b; 触发收缩&#xff1a;负载因子小于 0.1触发扩展&#xff1a;以下任一条件符合即可 服务器目前没有在执行 BGSAVE 命令或者 …

k8s核心资源

一、NameSpace对资源进行隔离&#xff0c;比如开发环境和测试环境等。命令# 查看所有命名空间的资源 kubectl get pod -A # 查看单独某个命名空间下的资源 kubectl get pod -n <空间名称> # 查看所有命名空间 kubectl get ns # 创建命名空间 kubectl create ns <空间名…

SpringAMQP

SpringAMQP是基于RabbitMQ封装的一套模板&#xff0c;并且还利用SpringBoot对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp的官方地址&#xff1a;Spring AMQP SpringAMQP提供了三个功能&#xff1a; 自动声明队列、交换机及其绑定关系&#xff08;RabbitAdmin&…

Hive自定义UDF函数及使用

目录 一、UDF概述 二、编写自定义UDF 1.创建项目 2.pom.xml文件添加依赖 3.编写工具类及自定义UDF类 4.打包 5.测试 jar 6.上传至服务器、HDFS并给jar包赋权 7.添加到hive类路径并创建临时函数 8.使用测试&#xff1a; 9.临时函数、永久函数 一、UDF概述 UDF全称&…

面试项目经验相关技巧

前言 面试问项目经验主要是想了解所做项目用到的技术&#xff0c;以及自己在项目中扮演的角色。 一、秒杀系统 秒杀系统往往不是咱的项目经验&#xff0c;但是面试可能会问&#xff0c;在说自己项目经验的时候也可以往秒杀和高并发上面带。 可能遇到的问题 高并发 一般就是…

阿里云KMS创建应用接入点

1.进入KMS控制台https://kms.console.aliyun.com/cn-beijing/applicationAP/list2.应用管理->创建应用接入点应用接入点可以想象成一个入口。入口打开的时候&#xff0c;运行在你服务器中的代码&#xff08;KMS客户端&#xff09;才可以与阿里云的KMS实例通讯。2.1设置入口名…

【软件测试】离开“浪浪山“测试人迎来的春天......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 这几年因为疫情、经…

Activiti7工作环境搭建_创建基础工程自动创建Activiti数据库表---工作流工作笔记004

然后我们开始来搭建activiti的环境 首先给idea安装activiti插件,从插件里搜索 actiBPM注意,这个直接在idea中搜索可能搜索不到,因为太旧了这个工具,新的idea已经不支持,需要手动去actiBpm 官网下载以后手动安装 下载就可以了 下载以后点击齿轮,然后选择从硬盘安装 选择下载好的…

注册公司认缴vs实缴,选择哪一个更好?

前言 上一篇说了在创业的时候先进行选择公司类型&#xff0c;然后在公司注册过程中都需要登记公司的注册资本&#xff0c;会涉及注册资金这一点&#xff0c;而现在有认缴制和实缴制&#xff0c;到底选择哪一个更好呢&#xff1f; 在选择之前&#xff0c;先来和大家分享下认缴制…

PyG-节点分类+链接预测+异常检测示例

引言图神经网络(Graph Neural Networks)是一种针对图结构数据(如社交图、网络安全网络或分子表示)设计的机器学习算法。它在过去几年里发展迅速&#xff0c;被用于许多不同的应用程序。在这篇文章中我们将回顾GNN的基础知识&#xff0c;然后使用Pytorch Geometric解决一些常见的…

idea本地debug调试DATAX插件运行

datax官方github地址&#xff1a;GitHub - alibaba/DataX: DataX是阿里云DataWorks数据集成的开源版本。 接触datax是看重他的数据采集功能和可以扩展插件的功能&#xff0c;根据官方说明&#xff0c;DATAX是以python来调用插件的运行json配置&#xff0c;但对于二次开发插件的…

nacos权限区分

背景 nacos的默认是不进行分配权限的&#xff0c;那么这样就带来了一个问题&#xff0c;如果多项目共同使用一个nacos&#xff0c;可以带了一个情况是开发人员误操作&#xff0c;把其他项目的nacos配置文件更改或者删除。那么如何解决这个问题呢&#xff1f;就是把nacos进行分…

网络知识详解之:网络攻击与安全防护

网络知识详解之&#xff1a;网络攻击与安全防护 计算机网络相关知识体系详解 网络知识详解之&#xff1a;TCP连接原理详解网络知识详解之&#xff1a;HTTP协议基础网络知识详解之&#xff1a;HTTPS通信原理剖析&#xff08;对称、非对称加密、数字签名、数字证书&#xff09;…

Kotlin 1.8.0 现已发布,有那些新特性?

文章目录**如何安装 Kotlin 1.8.0****如果您遇到任何问题****更多文章和视频**结语Kotlin 1.8.0 版本现已发布&#xff0c;以下是其部分最大亮点&#xff1a; JVM 的新实验性功能&#xff1a;递归复制或删除目录内容提升了 kotlin-reflect 性能新的-Xdebug编译器选项&#xff…

PCB铺铜技巧如何铺铜经验总结

&#x1f3e1;《总目录》 目录1&#xff0c; 什么是铺铜2&#xff0c;铺铜的好处3&#xff0c;如何铺铜4&#xff0c;铺铜的经验原则5&#xff0c;铺铜的注意事项1&#xff0c; 什么是铺铜 铺铜是指在PCB电气层添加整块的铜皮&#xff1b;铺铜包括电源层铺铜&#xff0c;地层铺…

openofdm03:Frequency Offset Correction

载波频率偏移&#xff08;Carrier Frequency Offset&#xff0c;CFO&#xff09;&#xff1a;发射机和接收机本振频率之差&#xff0c;会造成接收到的I/Q采样值的相位旋转。This symptom of this offset is a phase rotation of incoming I/Q samples (time domain). The CFO c…