1, 最小划分
给出一个正整数数组,写一个程序把这个整数数组分成S1跟S2两部分,使S1中的和跟S2中的和的差的绝对值最小。换句话讲,如果有一个一个整数数组 S 有 n 个数,如果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
和第一种类似,只不过题目是将整个过程分解了,求每一对的最小差,等于求两边相加后的最小差,也就是将数组分成两个最相近的部分。
本文通过三道编程题介绍了如何利用动态规划解决数组划分以达到差值最小,以及在购物优惠场景中如何选择商品使得优惠券得以充分利用。核心思路在于将问题转化为求解不超过一定值的最大和或最接近目标值的子集和。
1652

被折叠的 条评论
为什么被折叠?



