如何解决最小化两个不均匀连续数组的乘积之和 输出
我有一个优化问题,我需要最小化两个不均匀但连续的数组的和积,例如:
A = [1,2,3]
B = [4,9,5,3,10]
不允许对值进行混洗,即数组的索引必须保持不变。 换句话说,它是数组 A 对数组 B 以连续顺序的分布最小化。
或:鉴于 len(B)>=len(A)
在不改变数组 A 或 B 的顺序的情况下,最小化长度为 n 的数组 A 的值与数组 B 的 n 个值的和积。
在这种情况下,最小值为:
min_sum = 1*4 + 2*3 + 3*2 = 16
from itertools import combinations
sums = [sum(a*b for a,b in zip(A,b)) for b in combinations(B,len(A))]
min_sum = min(sums)
但是,我需要为多组数组执行此操作。我看到背包问题有很多重叠,我觉得应该用动态规划来解决。然而,我被困在如何编写一个有效的算法来执行此操作。
任何帮助将不胜感激!
解决方法
有两个列表
A = [1,2,3]
B = [4,9,5,3,10]
可以使用以下方法找到最佳和积:
min_sum = sum(a*b for a,b in zip(sorted(A),sorted(B)[:len(A)][::-1]))
如果总是给 A
排序,可以使用这个简化版本:
min_sum = sum(a*b for a,b in zip(A,sorted(B)[:len(A)][::-1]))
需要注意的重要部分:
- 您需要对
A
的因子进行排序。sorted(A)
将完成这项工作,而无需修改原始A
(与A.sort()
相反)。如果A
已经被排序,这一步可以省略。 - 您需要
N
中的B
最小值,其中N
是A
的长度。这可以通过sorted(B)[:len(A)]
完成
- 为了计算乘积的最小和,您需要将
A
的最高数乘以B
的最低数,A
的第二高数乘以第二低数B
。这就是为什么在获得N
的B
最低值后,顺序会被[::-1]
反转
输出
print(min_sum)
# 16
print(A)
# [1,3] <- The original list A is not modified
print(B)
# [4,10] <- The original list B is not modified
,
使用 Python,您可以轻松地对集合进行排序和翻转。您正在寻找的代码是
A,B = sorted(A),sorted(B)[:len(A)]
min_sum = sum([a*b for a,B[::-1])])
,
您可能需要从 B 中一个一个地获取值,并通过将每个值分配给一个键来保持列表的顺序。
A = [1,2]
B = [4,10]
#create a new dictionary with key value pairs of B array values
new_dict = {}
j=0
for k in B:
new_dict[j] = k
j+= 1
#create a new list of the smallest values in B up to length of array A
min_Bmany =[]
for lp in range(0,len(A)):
#get the smallest remaining value from dictionary new_dict
rmvky= min(zip(new_dict.values(),new_dict.keys()))
#append this item to minimums list
min_Bmany.append((rmvky[1],rmvky[0]))
#delete this key from the dictionary new_dict
del new_dict[rmvky[1]]
#sort the list by the keys(instead of the values)
min_Bmany.sort(key=lambda r: r[0])
#create list of only the values,but still in the same order as they are in original array
min_B =[]
for z in min_Bmany:
min_B.append(z[1])
print(A)
print(min_B)
ResultStr = ""
Result = 0
#Calculate the result
for s in range(0,len(A)):
ResultStr = ResultStr + str(A[s]) +"*" +str(min_B[s])+ " + "
Result = Result + A[s]*min_B[s]
print(ResultStr)
print("Result = ",Result)
输出如下:
A = [1,10]
1*4 + 3*3 + 2*2 +
Result = 17
然后改变A,输出变成:
A = [1,10]
1*4 + 2*3 + 3*2 +
Result = 16
,
不确定这是否有帮助,但无论如何。
这可以表述为混合整数规划 (MIP) 问题。基本上,一个带有一些边约束的分配问题。
min sum((i,j),x(i,j)*a(i)*b(j))
sum(j,j)) = 1 ∀i "each a(i) is assigned to exactly one b(j)"
sum(i,j)) ≤ 1 ∀j "each b(j) can be assigned to at most one a(i)"
v(i) = sum(j,j*x(i,j)) "position of each a(i) in b"
v(i) ≥ v(i-1)+1 ∀i>1 "maintain ordering"
x(i,j) ∈ {0,1} "binary variable"
v(i) ≥ 1 "continuous (or integer) variable"
示例输出:
---- 40 VARIABLE z.L = 16.000
---- 40 VARIABLE x.L assign
j1 j4 j5
i1 1.000
i2 1.000
i3 1.000
---- 40 VARIABLE v.L position of a(i) in b
i1 1.000,i2 4.000,i3 5.000
可爱的小 MIP 模型。
作为一个实验,我用 len(a)=50
和 len(b)=500
生成了一个随机问题。这导致具有 650 行和 25k 列的 MIP。在我的慢速笔记本电脑上在 50 秒内解决(证明全局最优)。
事实证明,在有向图上使用最短路径算法非常快。 Erwin 做了一个 post 展示了一个 MIP 模型。正如您在那里的评论部分所看到的,我们中的一些人独立尝试了最短路径方法,在 A 长度为 100,B 长度为 1000 的示例中,我们在 4 秒附近获得了最佳解决方案。>
,图形看起来像:
节点被标记为n(i,j)
,表示访问节点意味着将a(i)
分配给b(j)
。成本a(i)*b(j)
可以与任何传入(或任何传出)弧相关联。然后计算从src到snk的最短路径。
顺便说一句,你能谈谈这个问题的背景吗?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。