Учитывая вектор максимум 10 000 натуральных и отличных чисел, найдите 4 числа (a, b, c, d), таких что a + b + c = d - PullRequest
4 голосов
/ 04 июня 2010

Я решил эту проблему, следуя простому, но не оптимальному алгоритму. Я отсортировал вектор в порядке убывания и после этого вычитал числа от макс до мин, чтобы посмотреть, получу ли я + b + c = d. Обратите внимание, что я нигде не использовал тот факт, что элементы естественны, различимы и не более 10 000 элементов. Я полагаю, что эти детали являются ключом. У кого-нибудь здесь есть подсказка по оптимальному способу решения этой проблемы?

Заранее спасибо!

Позже Править: Моя идея звучит так:

'<<quicksort in descending order>>'

for i:=0 to count { // after sorting, loop through the array
    int d := v[i];
    for j:=i+1 to count {
        int dif1 := d - v[j];
        int a := v[j];

       for k:=j+1 to count {
           if (v[k] > dif1)
              continue;
           int dif2 := dif1 - v[k];
         b := v[k];

    for l:=k+1 to count {
 if (dif2 = v[l]) {
    c := dif2; 
     return {a, b, c, d}
 }
           }
        }
    }
}

Что вы думаете? (Извините за плохой отступ)

Ответы [ 3 ]

7 голосов
/ 04 июня 2010

Раствор в O (n 2 log n):

Вычисляет наборы всех возможных сумм и разниц:

{a i + a j : 1 <= i, j <= n} </p>

{a i -a j : 1 <= i, j <= n} </p>

(сохранить их в сбалансированном бинарном дереве поиска) и проверить, имеют ли они общий элемент. Если да, существуют i, j, k, l такие, что a i + a j = a k - a l , это i + a j + a l = a k .

Решение в O (a n log a n ), где a n - наибольшее число в векторе:

Вычислить полином

(x a 1 + x a 2 + ... + x a n ) 3

Вы можете сделать это в O (a n log a n ), используя Быстрое преобразование Фурье (сначала вычислите квадрат, затем третью степень; см. * 1069) * здесь для описания). Заметьте, что после умножения коэффициент x b i был сформирован из умножения x a i * x a j * x a k = x a i + a j + a k для некоторых i, j, k. Проверьте, есть ли степень x a l в полученном полиноме.

К сожалению, это позволяет использовать некоторые i, j, k дважды. Вычитание 3 (x 2a 1 + ... + x 2a n ) * (x a 1 + ... + x a n ) - 2 (x 3a 1 + ... + x 3a n ) удалит эти x a i + a j + a k .

4 голосов
/ 04 июня 2010

Существует алгоритм Шамира и Шропеля, который решает эту проблему во времени O (N ^ 2) и с памятью O (N), когда N - количество входов. Это в основном то, что предлагает sdcvvc, но вместо того, чтобы хранить множества {a i + a j } как единое целое, он будет повторно вычислять только суммы в соответствующих интервалах. Это экономит память, но не увеличивает сложность времени.

Ричард Шрёппель, Ади Шамир: «Алгоритм A T = O (2 ^ (n / 2)), S = O (2 ^ (n / 4)) для некоторых NP-полных задач». SIAM J. Comput. 10 (3): 456-464 (1981)

1 голос
/ 05 июня 2010

Вот @ комментарий MicSim к ответу @ sdcvvc , реализованный в Python:

def abcd(nums):
    sums = dict((a+b, (a,b)) for a, b in combinations(nums, 2))

    for c, d in combinations(sorted(nums), 2): # c < d
        if (d-c) in sums:
            a, b = sums[d-c]
            assert (a+b+c) == d
            if a == c or b == c: continue # all a,b,c,d must be different
            a,b,c = sorted((a,b,c))
            assert a < b < c < d
            return a,b,c,d

Где combinations() может быть itertools.combinations() или

def combinations(arr, r):
    assert r == 2 # generate all unordered pairs
    for i, v in enumerate(arr):
        for j in xrange(i+1, len(arr)):
            yield v, arr[j]

Это O (N 2 ) во времени и пространстве.

Пример:

>>> abcd(range(1, 10000))
(1, 2, 3, 6)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...