Python 最小化两个非均匀连续阵列的乘积之和

Python 最小化两个非均匀连续阵列的乘积之和,python,arrays,dynamic-programming,minimization,sumproduct,Python,Arrays,Dynamic Programming,Minimization,Sumproduct,我有一个优化问题,我需要最小化两个不均匀但连续的数组的和积,比如: A = [1, 2, 3] B = [4, 9, 5, 3, 2, 10] 不允许对值进行混洗,即数组的索引必须保持不变。 换句话说,它是阵列a在阵列B上按连续顺序的分布最小化 或者:假定len(B)>=len(A)使长度为n的数组A的值与数组B的n个值的和积最小化,而不改变数组A或B的顺序 在这种情况下,最低要求为: min_sum = 1*4 + 2*3 + 3*2 = 16 from itertools import

我有一个优化问题,我需要最小化两个不均匀但连续的数组的和积,比如:

A = [1, 2, 3]
B = [4, 9, 5, 3, 2, 10]
不允许对值进行混洗,即数组的索引必须保持不变。 换句话说,它是阵列a在阵列B上按连续顺序的分布最小化

或者:假定
len(B)>=len(A)
使长度为n的数组A的值与数组B的n个值的和积最小化,而不改变数组A或B的顺序

在这种情况下,最低要求为:

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)

解决这个问题的强力方法是:

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)

但是,我需要对多组数组执行此操作。我看到背包问题有很多重叠,我觉得应该用动态规划来解决。然而,我被困在如何编写一个有效的算法来执行这项任务


任何帮助都将不胜感激

使用Python,您可以轻松地对集合进行排序和翻转。您要查找的代码是

A, B = sorted(A), sorted(B)[:len(A)]
min_sum = sum([a*b for a,b in zip(A, B[::-1])])
有两张名单

A = [1, 2, 3]
B = [4, 9, 5, 3, 2, 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
    因子<代码>排序(A)将执行此任务,而不修改原始的
    A
    (与
    A.sort()
    )相反)。如果已给出排序的
    A
    ,则可以省略此步骤
  • 您需要
    B
    中的
    N
    最低值,其中
    N
    A
    的长度。这可以通过排序(B)[:len(A)]
  • 为了计算乘积的最小和,您需要将最高的
    A
    与最低的
    B
    相乘,将第二高的
    A
    与第二低的
    B
    相乘。这就是为什么在获得
    N
    最低值
    B
    后,顺序会与
    [:-1]
输出
打印(最小和)
# 16
印刷品(A)

#[1,2,3]您可能需要从B中逐个获取值,并通过将每个值分配给一个键来保持列表的顺序

A = [1, 3, 2]
B = [4, 9, 5, 3, 2, 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, 3, 2]
B = [4, 9, 5, 3, 2, 10]
1*4 + 3*3 + 2*2 + 
Result =  17
然后更改A,输出变为:

A = [1, 2, 3]
B = [4, 9, 5, 3, 2, 10]
1*4 + 2*3 + 3*2 + 
Result =  16

不确定这是否有用,但无论如何

这可以表述为一个混合整数规划(MIP)问题。基本上,一个带有一些边约束的指派问题

  min sum((i,j),x(i,j)*a(i)*b(j))
      sum(j, x(i,j)) = 1    ∀i        "each a(i) is assigned to exactly one b(j)"
      sum(i, x(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秒(证明了全局最优)就解决了问题。

结果表明,在直连图上使用最短路径算法非常快。欧文做了一个演示,展示了一个MIP模型。正如您在评论部分所看到的,我们中的一些人独立地尝试了最短路径方法,在示例中,长度a为100,长度B为1000,我们在大约4秒的时间内得到了最佳解决方案。

图表可以如下所示:

节点标记为
n(i,j)
,表示访问节点意味着将
a(i)
分配给
b(j)
。成本
a(i)*b(j)
可与任何传入(或传出)弧相关联。然后计算从src到snk的最短路径


顺便说一句,你能谈谈这个问题的背景吗?

在python中,你应该注意你所说的数组/列表。示例中的变量
A
B
set
s。确保你知道其中的区别!正如@AnsFourtyTwo提到的,您需要用[]声明数组。请看这里,以获取长度为n[(然后您可以用数组中的最大值乘以其中的每一个值,直到数字用完为止)的B数组中的最小值。感谢您的回答!不幸的是,在排序A时,违反了A的有序数组的要求。例如
A=[1,3,2]
。然后解决方案将是:
1*4+3*3+2*2=17
。然而,在这个解决方案中,您将A排序为
A=[1,2,3]
,结果仍然是16,这是不允许的。也许我在这里遗漏了一些内容,但它似乎几乎就在那里,但还没有完全实现。如果我没有足够清楚地阐述这个问题,我感到抱歉。如果
A=[1, 3, 2]
给出,预期结果是什么?
16
17
?即使没有排序
A
,你也可以通过
1*4+3*2+2*3
计算最小值。哦,哇,我想我完全理解了你的问题。第一次阅读时很难理解。这非常有用!我希望这是一个MIP问题。我正在探索贪婪算法,如Dijkstra的算法,以提高时间复杂度。您的模型非常有用,但我在编码MIP问题方面没有太多经验。我曾使用过一些API,如GUROBI,但我不太确定如何在这里实现您的代码。我需要一些第三方优化模块吗?我是curi我们来看看你是如何实现这个模型的。谢谢!!!我使用了GAMS+Cplex。但是,这个模型非常简单,你可以使用任何解算器或建模工具。我没有看到任何东西会让Gurobi Python API变得特别困难。我目前正在通过Gurobi实现MIP。但是,我在定义c时遇到了一些问题这里是我目前正在使用的:
#二进制变量x=m.addVars(total_cost,name='assign')#约束c1=m.addConstrs((x.sum('*',a)=1表示a中的a),'a')#每个a(a)精确地分配给1b(B)c2=m.addConstrs((x.sum(B,'*'))只需为lhat使用一个循环。