Biggest possible sum of multiples

时间:2015-09-25 10:04:43

标签: c++ arrays sum mathematical-optimization linear-programming

How would you solve this?

You have 2 arrays, each with n numbers, n <= 500. You can choose one number from the first three in first array and multiple it with first number in second array. Continue doing this until every number is used. Write the biggest possible sum of these multiples.

For example:

n = 4;
first array contains : 16 6 2 10
second array contains : 3 8 12 9
Output : 336

For first number from second array - 3 - you can choose from 16,6 and 2. Best option is to choose 2. Sum is now 3 * 2 = 6;
For second number from second array - 8 - you can choose from 16,6,10 (number 2 is already used). Best option is to choose 6. Add 8 * 6 to sum, so sum is now 54.
For third number from second array - 12 you can choose from 16,10 (number 2 and 6 are already used). Best option is to choose 16. Add 12 * 16 to sum, so sum is now 246.
For last number from second array - 9 - you can choose only 10.Add 9 * 10 to sum, so sum is now 336.

I had few ideas, but every one of them was wrong. For example I tried to sort both arrays and then biggest number in second array multiply with biggest possible number in first array (because 1. number in second array can choose only from 1.-3. position in first array, second number can choose only from 1.-4. etc.), but this isn't right. Also I have some more solutions, but too hard for me to explain them, because I don't know how to express it in English(But I could post a code and try to explain it) , and they also aren't right.
EDIT: I have found some algorithms that may be solution for my problem. First is
Hungarian algorithm传递变量,其次是Auction Algorithm。这是我第一次接触线性编程...我理解匈牙利算法是如何工作的,但我无法实现它。在拍卖算法中,我甚至不确定它是如何工作的。另外,我不知道它们是否足够快。匈牙利算法的时间复杂度为O(n ^ 3),在我的情况下,我n <= 500,因此对于最大n,它可能持续太长时间。同样在Assignment problem中,每个“工人”都可以做每一份“工作”,但就我而言,事实并非如此 它可能是Max flow problem,但我对此不太确定,因为我需要一个完美的匹配 - 这意味着每个顶点都匹配 - 我不知道这个算法是否有保证。

3 个答案:

答案 0 :(得分:0)

首先,对于我来说,不清楚为什么第二个数组中的第一个数字我们应该只使用第一个数组中的三个第一个项目,而对于第二个数组中的每个其他数字我们使用来自第二个数组的任何数字第一个阵列。

但是,我们可以将这两个数组表示为二分图,其中第二个数组中的每个数字都连接到第一个数组中的(每个?*)数字。在该图中,每个边(u,v)的权重等于数组(u * v)中两个数的相乘。 对于给定的图表,您应该解析max flow problem

*如果我正确理解了问题,你应该将第二个数组中的第一个数字与来自第一个数组的前3个数字连接起来,将第二个数字中的每个数字连接起来,第一个数字来自第一个数组。

答案 1 :(得分:0)

  

继续这样做直到使用每个数字。写出这些倍数的最大可能总和

这看起来像是一个离散的组合优化问题。我想到的第一个解决此问题的算法是使用 Branch and Bound 算法。

它允许反向跟踪,您可以通过递归实现它。

答案 2 :(得分:0)

我使用JuliaJuMP中实现了混合整数规划方法。它适用于您的示例,一般概念应该有效,但可能需要更多测试!

即使你不熟悉朱莉娅,它也应该是可读的。请记住,索引从1开始(如在Matlab中)而不是0(如在C,Java中......)

基本思想如下(阅读评论以了解更多):定义具有维度(N,N)的二进制变量X:如果X [a,b] == 1 - &gt;在步骤a中选择了[b]。

最难理解的部分是bigM-Formulation,它只是评论中解释的逻辑的不同的表述。它的唯一目的是线性化

{
  "rules": {
    "list": {
      ".indexOn": ["foo"],

      "$item": {
        "foo": {
          ".validate": "newData.isString()"
        }
      }

    }
  }
}

输出:

using JuMP

N = 4
A = [16 6 2 10]
B = [3 8 12 9]

# MODEL
m = Model()

# VARS
@defVar(m, x[1:N, 1:N], Bin)  # N steps, N vars/indices // binary

# CONSTRAINTS
# (1) exactly one var chosen in each step
for s = 1:N 
    @addConstraint(m, sum(x[s,:]) == 1)
end

# (2) each var is chosen exactly once
for v = 1:N 
    @addConstraint(m, sum(x[:,v]) == 1) 
end 

# (3) if var v chosen in step s -> are enough predecessors already taken away -> is in positions 1:3?
for s = 1:N 
    for v = 1:N 
        needed_pops_before = v - 3
        if needed_pops_before > 0
            # bigM formulation:
            # formula: (x[s,v] == 1) -> sum of predecessors taken away until now >= needed_pops
            #   use deMorgan-law -> !(x[s,v] == 1) -> sum >= needed_pops    
            #   formulate with bigM = N because needed_pops limited by N-3
            @addConstraint(m, N * (1-x[s,v])  + sum{x[ss,jj], ss=1:s-1, jj=1:v-1} >= needed_pops_before)
        end 
    end 
end

# OBJECTIVE
@setObjective(m, Max, sum{B[s] * A[v] * x[s,v], s=1:N, v=1:N})

# SOLVE
status = solve(m)

# OUTPUT
println("Objective is: ", getObjectiveValue(m))
println("Solution: ")
for s = 1:N 
    for v = 1:N 
        if getValue(x[s,v]) > 0.00001
            print(A[v], " ")
        end 
    end
end