#algorithm #performance #math
#алгоритм #Производительность #математика
Вопрос:
Каков был бы наилучший способ найти наилучшую комбинацию массива элементов с заданной ценой, чтобы цена была максимальной, при условии, что некоторые элементы нельзя комбинировать с другими.
Пример:
items = [
{
id: 1
price: 1000
},
{
id: 2
price: 3000
},
{
id: 3
price: 7000
},
{
id: 4
price: 2500
},
{
id: 5
price: 5000
}
];
not_combinable_item_pairs = [
{idA: 3, idB: 5},
{idA: 1, idB: 2},
{idA: 2, idB: 3},
];
В этом примере элемент 3 не может быть объединен с элементом 5 и т. Д…
То, о чем я думал до сих пор, заключается в том, что вы можете исключить все элементы, которые могут быть объединены с любым другим элементом, потому что они могут быть добавлены к любой комбинации.
В моем примере это будет элемент 4, потому что элемент 4 можно комбинировать со всеми другими элементами. Поэтому нужно было бы только изучить другие элементы.
Далее я просмотрел соединения, но не смог найти алгоритм, который решает проблему в целом. Я был бы признателен за любые предложения, идеи или ссылки на литературу по такого рода проблемам.
Комментарии:
1. Для меня это похоже на задачу линейной оптимизации, вы хотите максимизировать целевую функцию, при этом соблюдая определенные ограничения, которые я бы рекомендовал искать вместе с симплексным алгоритмом.
2. @hbejgel Спасибо. Я посмотрел на симплексный алгоритм, но я не совсем понимаю, как его применять
Ответ №1:
Всего есть
N (N-1)/2 — длина (исключения)
возможные пары, которые необходимо будет протестировать. Я ваш случай: 10-3 = 7.
Я сам поиграл с этим и придумал следующее:
const items = [1000,3000,7000,2500,5000], res=[],
n=items.length,
na=[[4,2],[0,1],[1,2]],
nas=na.map(e=>e.sort().join(" "));
for (let i=0;i<n;i )
for (let j=i 1;j<n;j ){
let k=i " " j;
if(nas.indexOf(k)<0) res.push([k,items[i] items[j]]);}
console.log(res.sort((a,b)=>b[1]-a[1]));
Я немного сократил ваш синтаксис: Я избавился от id
свойства и использовал индекс элементов напрямую, но это лишь косметический момент. Очевидно, что мои индексы теперь начинаются с 0, а не с 1. Массив na
(«неприменимо») содержит запрещенные комбинации, не обязательно в любом порядке, и nas
является их строковой версией, которую я создал для более быстрого поиска.
В моем фрагменте будут перечислены разрешенные комбинации в порядке убывания их сумм.
Обновить
Поскольку OP дал понять, что ищутся комбинации любой длины, я переписал свой фрагмент.
Очевидно, что общее количество комбинаций теперь
2^N — 1 — длина(исключения)
поскольку пустое множество («без элементов») исключается.
const items = [1000,3000,7000,2500,5000],
res=[],
n=items.length,
na=[[2,4],[0,1],[1,2]];
function combine(arr,ex){
const n=arr.length,res=[];
function cc(iarr,j){ // "concat with sum"
let jarr=iarr.concat(j);
jarr.sum=(iarr.sum||0) arr[j];
return jarr;
}
function cmb(idx,i){
for (let j=i;j<n;j )
if(!na.some(([a,b])=>idx.indexOf(a)>-1amp;amp;b==j))
cmb(res[res.length]=cc(idx,j),j 1)
}
cmb([],0); // start the recursive call chain here
return res.sort((a,b)=>b.sum-a.sum);
}
let comb=combine(items,[]);
console.log(comb.map(e=>e.join(",") "=" e.sum),
comb.length)
В этой версии я использую рекурсивную функцию cmb()
для перебора всех разрешенных комбинаций, отслеживания задействованных индексов и одновременного накопления суммы с помощью моей пользовательской функции cc()
объединения.
combine()
возвращает массив со всеми разрешенными комбинациями, отсортированными в порядке убывания их сумм.
Ответ №2:
Это проблема нахождения независимого множества с максимальным весом в графе (где not_combinable_item_pairs
находятся ребра).
Насколько я понимаю, полиномиальные решения существуют только для некоторых специальных типов графов, в то время как в общем случае это NP-сложная задача.
Итак, чтобы получить точное решение, вам нужно проверить все подмножества (для N вершин существует 2 ^ N подмножеств).
Комментарии:
1. Я также провел еще несколько исследований и пришел к проблеме клики, которая является np-полной проблемой. Далее я нашел этот отличный алгоритм https://arxiv.org/pdf/1503.04794.pdf . Мой подход состоял бы в том, чтобы создать комбинируемый массив из некомбинируемого массива (мои ребра графика), а затем найти все подграфы, которые полностью связаны друг с другом. Из всех них я бы выбрал «лучший». Согласны ли вы с этим подходом или я что-то пропустил?
2. Я боюсь, что проблема с кликами не близка к вашей проблеме. И что вы имеете в виду
make a combinable array from the non-combinable array
? Обратный график, где запускаются все ребра?3. Да, точно, я подумал, что если я определю обратные ребра, достаточно найти все подграфы, которые связаны друг с другом.