Как найти все совпадающие числа, которые суммируются в' N ' в заданном массиве
Моя цель здесь состоит в том, чтобы найти все возможные комбинации, которые суммируются в заданную сумму. Например, если массив 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 ответов:
#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()); }
Задача, которую вы описываете, также известна как задача суммы подмножеств , которая являетсяNP-полной . Лучшее, чего вы можете достичь, - это экспоненциальный алгоритм времени, который пробует все возможные подмножества вашего массива/набора.
Если значения невелики, скажем, ваша сумма ограничена M, вы можете использовать динамическое программирование. Предположим, что существует N элементов.
Представьте, что у вас есть матрицаDP[M][N]
. ЯчейкаDP[m][n]
означает: сколько комбинаций первых n элементов суммируют ровно m? Анализируя каждый элемент, вы можете включить или не включить его в некоторую комбинацию. Затем вы получаете повторение (заботясь о несвязанных значениях)DP[m][n] = DP[m][n-1] + DP[m - v[n]][n - 1]
Первый член rhs означает, что вы рассматриваете все суммы, которые делают не использовать n-го элемента и второй срок все суммы, которые использовать энный элемент. Вы начинаете с базиса
DP[0][0] = 1
, так как пустое множество является допустимой комбинацией, которая суммирует 0. Искомое значение находится в DP[M][N].Это псевдополином, хотя,
O(MN)
.
Это вариация NP-полного Задача о рюкзаке , Задача о сумме подмножеств . Задача о полноразмерном рюкзаке может быть линейно сведена к вашей задаче путем последовательного понижения N. вы не найдете точного алгоритма для своей задачи, который работает быстрее, чем экспоненциально в N, если P != NP держит.
Однако известны полиномиальные приближения по времени.
Это связано с разделением в теории чисел, и его можно решить с помощью динамического программирования.
Пусть
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 = []
Это типичное домашнее задание.