Как найти все совпадающие числа, которые суммируются с 'N' в данном массиве - PullRequest
2 голосов
/ 21 июля 2010

Моя цель здесь - найти все возможные комбинации, которые суммируются с заданной суммой. Например, если массив 2 59 3 43 5 9 8 62 10 4, и если общее количество равно 12, то возможные комбинации

2 10
3 9
8 4
5 3 4

Вот первый набор кода, который я написал. Хотите знать, как лучше всего это сделать.

   int find_numbers_matching_sum(int *number_coll, int total)
{

    int *search_till = lower_bound(number_coll,number_coll+TOTAL_SIZE, total);
    int location = search_till - number_coll;
    if (*search_till > total && location > 0 )
    {
        --location;
    }

    while ( location >= 0 )
    {
        find_totals(number_coll,total,location);
        --location;
    }
    return 1;
}

int find_totals(int *number_coll, int total, int end_location)
{
    int left_ones = total - number_coll[end_location];
    int curloc = end_location;
    int *search_till = 0;
    int location ;
    int all_numbers[10];
    int i = 0;

    all_numbers[i] = number_coll[end_location];
    while ( left_ones && curloc >= 0 )
    {
        search_till = lower_bound(number_coll,number_coll+end_location, left_ones);
        location = search_till - number_coll;
        if (*search_till > left_ones && location > 0 )
        {
            --location;
        }
        else if ( left_ones < *search_till )
        {
            break;
        }
        curloc=location;
        left_ones = left_ones - number_coll[curloc];
        all_numbers[++i] = number_coll[curloc];
        end_location = curloc - 1;
    }

    if ( !left_ones )
    {
        while ( i>=0)
        {
            cout << all_numbers[i--] << ' ';
        }
    }
    cout << endl;
    return 1;


}

Ответы [ 6 ]

6 голосов
/ 21 июля 2010

Проблема, которую Вы описываете, также известна как Проблема Суммы Подмножества , которая NP-полная .Лучшее, чего вы можете достичь, - это экспоненциальный алгоритм времени, который пробует все возможные подмножества вашего массива / набора.

5 голосов
/ 21 июля 2010

Это проблема суммы подмножеств ( NP-Complete ), и пока P? = NP, существует только экспоненциальное решение.

С xkcd

3 голосов
/ 21 июля 2010

Если значения не велики, скажем, ваша сумма ограничена М, вы можете использовать динамическое программирование .Предположим, есть N предметов.

Представьте, что у вас есть матрица DP[M][N].Ячейка DP[m][n] означает: сколько комбинаций первых n элементов составляют в точности m?

Анализируя каждый элемент, вы можете включить или не включить его в какую-либо комбинацию.Затем вы получите повторение (с учетом внешних значений)

DP[m][n] = DP[m][n-1] + DP[m - v[n]][n - 1]

первый член rhs означает, что вы рассматриваете все суммы, в которых не используется n-й элемент, а второй член - все суммыкоторые используют n-й предмет.Вы начинаете с базиса DP[0][0] = 1, поскольку пустой набор является допустимой комбинацией с суммой 0. Желаемое значение находится в DP [M] [N].

Это псевдополином, хотя O(MN),

3 голосов
/ 21 июля 2010

Это разновидность NP-полной задачи о ранце , задачи о подмножестве сумм . Полноценную задачу о ранце можно линейно свести к вашей задаче, последовательно уменьшив N. Вы не найдете точного алгоритма для вашей задачи, который работает быстрее, чем экспоненциально в N, если выполняется P! = NP.

Однако аппроксимации полиномиального времени известны.

2 голосов
/ 22 июля 2010
#include <iostream>
#include <vector>

using namespace std;

struct State {
    int v;
    const State *rest;
    void dump() const {
        if(rest) {
            cout << ' ' << v;
            rest->dump();
        } else {
            cout << endl;
        }
    }
    State() : v(0), rest(0) {}
    State(int _v, const State &_rest) : v(_v), rest(&_rest) {}
};

void ss(int *ip, int *end, int target, const State &state) {
    if(target < 0) return; // assuming we don't allow any negatives
    if(ip==end && target==0) {
        state.dump();
        return;
    }
    if(ip==end)
        return;
    { // without the first one
        ss(ip+1, end, target, state);
    }
    { // with the first one
        int first = *ip;
        ss(ip+1, end, target-first, State(first, state));
    }
}

int main() {
    int a[] = { 2,59,3,43,5,9,8,62,10,4 };
    int * start = &a[0];
    int * end = start + sizeof(a) / sizeof(a[0]);
    ss(start, end, 12, State());
}
1 голос
/ 21 июля 2010

Это относится к Разделу в теории чисел, и это можно решить с помощью динамического программирования.

Пусть n будет суммой. Пусть parts будет списком элементов. Мы предполагаем, что они являются положительными целыми числами.

if parts == []
then f(n,parts) = [] 
else let parts = x::queue and f(n,parts) = union(L1, L2)

where:

L1 = f(n, queue)

if n-x>0
then let result = f(n-x, queue) and L2 = concatenation([x], result)
else if n-x==0, L2 = [x]
else L2 = []

Это типичная домашняя работа.

...