【动态规划】背包问题的几种变形

本文通过三道编程题介绍了如何利用动态规划解决数组划分以达到差值最小,以及在购物优惠场景中如何选择商品使得优惠券得以充分利用。核心思路在于将问题转化为求解不超过一定值的最大和或最接近目标值的子集和。
Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

1, 最小划分

LintCode 炼码

给出一个正整数数组,写一个程序把这个整数数组分成S1跟S2两部分,使S1中的和跟S2中的和的差的绝对值最小。换句话讲,如果有一个一个整数数组 Sn 个数,如果Subset1有 m 个数,Subset2必须有 n-m 个数并且 abs(sum(Subset1) – sum(Subset2)) 应该最小。

        #x,sum-x
        #sum-x-x最小
        #x最接近sum/2
        #转换成01背包sum/2就是无价值的01背包中的背包容量
        m=sum(nums)//2
        n=len(nums)
        dp=[[False]*(m+1) for i in range(n+1)]
        dp[0][0]=True
        for i in range(1,n+1):
            dp[i][0]=True
            for j in range(1,m+1):
                if j-nums[i-1]>=0:
                    dp[i][j]=dp[i-1][j] or dp[i-1][j-nums[i-1]]
                else:
                    dp[i][j]=dp[i-1][j]
        for i in range(m,-1,-1):
            if dp[n][i]==True:
                k=i
                break
        return sum(nums)-2*k

这种题牵扯到了数学上的思维,要求将数组分成尽可能相等的情况,我们先设一半是x,则另一半则是sum-x,依据题意,

让求min(sum-x-x)即min(sum-2x)

则求sum>2x中x的最大值,

即x<sum/2中x的最大值,

即容量为sum/2时,最多能装多满

2,外卖满减

链接:外卖满减_美团笔试题_牛客网
来源:牛客网

你打开了美了么外卖,选择了一家店,你手里有一张满 X 元减 10 元的券,店里总共有 n 种菜,第 i 种菜一份需要 Ai 元,因为你不想吃太多份同一种菜,所以每种菜你最多只能点一份,现在问你最少需要选择多少元的商品才能使用这张券。

n,x=map(int,input().split())
l=list(map(int,input().split()))
m=sum(l)-x
dp=[[False]*(m+1) for i in range(n+1)]
dp[0][0]=True
for i in range(1,n+1):
    dp[i][0]=True
    for j in range(1,m+1):
        if j-l[i-1]>=0:
            dp[i][j]=dp[i-1][j] or dp[i-1][j-l[i-1]]
        else:
            dp[i][j]=dp[i-1][j]
for i in range(m,-1,-1):
    if dp[n][i]==True:
        k=i
        break
print(sum(l)-k)

同样的,求超过x,但最小的价格

像这种题我们一般写动态规划遇到的都是小与m,求最大的

我们很容易会想到转换一下, 

让m=sum(l)-x,这样我们就变成了求不超过m的最大值这种我们常见的无价值的背包问题

我们最后只需让结果变为sum(l)-k再变回路就行了

3,最后一块石头的重量

力扣

        n=len(stones)
        m=sum(stones)//2
        dp=[[0]*(m+1) for i in range(n+1)]
        dp[0][0]=True
        for i in range(1,n+1):
            dp[i][0]=True
            for j in range(1,m+1):
                if j-stones[i-1]>=0:
                    dp[i][j]=dp[i-1][j] or dp[i-1][j-stones[i-1]]
                else:
                    dp[i][j]=dp[i-1][j]
        for i in range(m,-1,-1):
            if dp[n][i]==True:
                k=i
                break
        return sum(stones)-2*k

和第一种类似,只不过题目是将整个过程分解了,求每一对的最小差,等于求两边相加后的最小差,也就是将数组分成两个最相近的部分。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值