最大产品总和

时间:2015-08-09 09:49:50

标签: algorithm sequence maximize

我有以下问题。

给定N个数字,范围-100..100。

需要重新排列元素以获得最大的产品价值总和。 此任务中的乘积和定义为A1 * A2 + A2 * A3 ... AN-1 * AN

例如,给定数字10 20 50 40 30。

然后,我们可以按照以下方式重新排列它们: 从左边10,30,50,40,20有最大10×30 + 30×50 + 50×40 + 40×20 = 4600

这个想法是对序列进行排序,然后将最大数字放在新序列的中间,然后将下一个最大数字放在右边,然后放到左边,依此类推。 但是,关于负数,这是行不通的。

我尝试过以下算法:

1)排序初始序列 2)如上所述处理正数和零值 3)处理负数如何描述 4)从正序中找到最小数,它可以是左或右元素,并在此数字处理后的负序之前加上。

例如,给定序列:

1,-2,3,-4,5,-6,7,-8,9,10,11,12,13,14,15,-16

预计产品的最大总和为1342。

我的算法给出了下一个重新排列:

3,7,10,12,14,15,13,​​11,9,5,1,-4,-8,-16,-6,-2

产品总和为1340。

这似乎有效,但事实并非如此。

你能告诉我吗?

2 个答案:

答案 0 :(得分:0)

你的方法很合理,但你必须将正数和负数分开。

对数组进行排序并将其拆分为左右部分,一个包含所有负数,另一个包含所有非负数。像往常一样重新排列它们,中间的最大(绝对)值和两侧交替放置的递减值,但要确保每个部分中的最小值位于相反的两端。

具体来说,绝对值最小的负数应该是左边部分的最后一个元素,而具有最小值的非负值应该是右边部分的第一个元素。

然后连接这两个部分并计算相邻产品的总和。

这是一个有效的例子:

arr = [2, 3, 5, -6, -2, -5]
arr.sort() = [-6, -5, -2, 2, 3, 5]
left, right = [-5, -6, -2], [2, 5, 3]
max_sum_of_product = -5*-6 + -6*-2 + -2*2 + 2*5 + 5*3 = 63

我没有正确的正式证据,但这种方法与输入数组的所有排列上的强力搜索结果相同:

def max_sum_of_products(arr):
  from itertools import permutations
  n = len(arr)

  ###### brute force method
  max1 = max([sum([a[x-1]*a[x] for x in range(1,n)]) for a in permutations(arr)])

  ###### split method
  lo, hi = [x for x in arr if x<0], [x for x in arr if x>=0]
  lo.sort()
  hi.sort()
  lo_ordered, hi_ordered = [], []
  t = (len(lo)%2 == 1)
  for x in lo:
    if t:
      lo_ordered = lo_ordered + [x]
    else:
      lo_ordered = [x] + lo_ordered
    t = not t
  t = (len(hi)%2 == 0)
  for x in hi[::-1]:
    if t:
      hi_ordered = hi_ordered + [x]
    else:
      hi_ordered = [x] + hi_ordered
    t = not t
  arr = lo_ordered + hi_ordered
  max2 = sum([arr[x-1]*arr[x] for x in range(1,n)])

  return (max1, max2)

def test():
  from random import randint
  for i in range(10):
    a = []
    for j in range(randint(4,9)):
      a = a + [randint(-10,10)]
    print a,
    (max1,max2) = max_sum_of_products(a)
    if max2!=max1:
      print "bad result :-("
    else:
      print max1

test()

答案 1 :(得分:0)

我在java中编写了一个方法,它将数组作为输入,并返回产品对的最大总和作为输出。

首先我计算负部分,然后计算正部分,然后返回它们的计算总和。 在计算负面部分时,如果元素的数量是奇数,则需要避免剩余的元素(因为它可以乘以0并且无效),我们这样做,以便负增加将降低总和。 所有其他负面项目都需要成对相乘并加总。

然后进入第二个正面部分,当我们看到1时,如果元素的数量是奇数,我们需要添加它,否则只需乘以前进。

 public static long sum(int arr[]) {
    Arrays.sort(arr);
    long ans = 0;
    long ans1 = 0;
    boolean flag = false;
    boolean flag2 = false;
    int[] arr1 = new int[arr.length];
    int[] arr2 = new int[arr.length];
    int i = 0;
    while (arr[i] < 0) {
        arr1[i] = arr[i];
        i++;
    }
    if (arr[i] == 0) flag = true;

    if (i % 2 == 0) {                              //even -6,-5,-3,-2,-1
        for (int j = 0; j < i - 1; j += 2) {
            ans = arr1[j] * arr1[j + 1];
        }
    } else {
        if (flag) {
            for (int j = 0; j < i - 2; j += 2) {
                ans = arr1[j] * arr1[j + 1];
            }
        }
    }
    int j = 0;
    while (i<arr.length) {
        arr2[j] = arr[i];
        i++;
        j++;
    }

    if (arr2[j] == 1) flag2 = true;

    if (i % 2 == 0) {
        for (int k=i-1; k>0; k-=2) {
            ans1 = arr2[k] * arr2[k-1];
        }
        if (flag2) ans1 = ans1 + 1;
    } else {
        for (int k=arr2.length-1; k>1; k-=2) {
            ans1 = arr2[k] * arr2[k-1];
        }
        ans1 = ans1 + arr2[0];
    }
    return ans + ans1;
}