разделите список на две части, чтобы их сумма была ближе друг к другу
Это жесткий проблема алгоритмов, что :
разделите список на 2 части (sum), чтобы их сумма была ближе всего друг к другу
длина списка равна 1
например : 23 65 134 32 95 123 34
1.sum = 256
2.sum = 250
1.список = 1 2 3 7
2.список = 4 5 6
У меня есть алгоритм, но он не работа для всех входов.
- init. списки list1 = [], list2 = []
- элементами сортировки (по заданному списку) [23 32 34 65 95 123 134]
- поп последний (МАКС один)
- вставить в список, который отличается менее
реализация : list1 = [], list2 = []
- выберите 134 вставить list1. list1 = [134]
- выберите 123 вставить list2. потому что, если вы вставляете в list1, разница становится больше
3. выберите 95 и вставьте list2 . потому что sum(list2) + 95 - sum (list1) меньше.
и так далее...
3 ответов
проблема в NPC, но для нее есть псевдополиномиальный алгоритм, это 2-раздел проблема, вы можете следовать пути псевдо-полиномиального алгоритма времени для sub set sum проблема для решения этой проблемы. Если входной размер полиномиально связан с входными значениями, то это можно сделать за полиномиальное время.
в вашем случае (Весы суммы
пусть Sum = сумма весов, мы необходимо создать двумерный массив A, а затем построить A, столбец за столбцом
A[i, j] = true if (j == weight[i] или j - weight[i] = weight[k] (k находится в списке)).
создание массива с помощью этого алгоритма занимает O (n^2 * sum/2).
наконец, мы должны найти самый ценный столбец, который имеет истинное значение.
вот пример:
элементов:{0,1,2,3} весы: {4,7,2,8} => sum = 21 sum/2 = 10
items/weights 0| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
---------------------------------------------------------
|0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0
|1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0
|2 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1
|3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1
Итак, потому что a[10, 2] == настоящий раздел 10, 11
это алгоритм, который я нашел здесь и отредактировал немного, чтобы решить вашу проблему:
bool partition( vector< int > C ) {
// compute the total sum
int n = C.size();
int N = 0;
for( int i = 0; i < n; i++ ) N += C[i];
// initialize the table
T[0] = true;
for( int i = 1; i <= N; i++ ) T[i] = false;
// process the numbers one by one
for( int i = 0; i < n; i++ )
for( int j = N - C[i]; j >= 0; j--)
if( T[j] ) T[j + C[i]] = true;
for(int i = N/2;i>=0;i--)
if (T[i])
return i;
return 0;
}
Я только что вернул первый T[i], который является истинным вместо возврата T[N/2] (в порядке max to min).
найти путь, который дает это значение не трудно.
вы можете переформулировать это как проблема с рюкзаком.
У вас есть список предметов с общим весом M, которые должны быть установлены в бункер, который может содержать максимальный вес M/2. Предметы, упакованные в корзину, должны весить как можно больше, но не больше, чем в корзине.
для случая, когда все веса неотрицательны, эта проблема только слабо NP-complete и имеет полиномиальные временные решения.
описание динамических программные решения для этой проблемы можно найти на Википедия.
эта проблема, по крайней мере, так же трудно, как NP-полная проблема подмножество сумме. Ваш алгоритм-жадный алгоритм. Этот тип алгоритма быстр и может быстро генерировать приблизительное решение, но не может найти точное решение NP-полной задачи.
подход грубой силы, вероятно, самый простой способ решить вашу проблему, хотя это будет замедляться, если слишком много элементов.
- попробуйте все возможные способы разбиение элементов на два набора и вычисление абсолютной разницы в суммах.
- Выберите раздел, для которого абсолютная разница минимальна.
генерация всех разделов может быть выполнена путем рассмотрения двоичного представления каждого целого числа от 0 до 2^n, где каждая двоичная цифра определяет, находится ли соответствующий элемент в левом или правом разделе.