Как распределить количество элементов в ведре так, чтобы оно было в пределах диапазона — алгоритм

Я решал проблему, где, скажем, у меня есть 50 элементов n1, n2, n3, ... , n50.

Теперь у меня есть ограниченное количество ведер, скажем, 5 ведер, и ведро может содержать диапазон, скажем, только от 100 до 150 (что есть не что иное, как сумма элементов в этом ведре), но не менее 100 и не более 150. .

Какой алгоритм наиболее подходит для решения этой задачи, чтобы использовались все 5 ведер и все элементы (n1, n2, n3, ...) также были израсходованы.

Если ведро не используется или какой-либо элемент пропущен, алгоритм просто возвращает «InvalidConditionsFound».

Я попробовал Knapsack, который дает вам комбинацию, максимально близкую к заданному числу, но как получить ее в пределах диапазона, а также убедиться, что он выбирает мудро, чтобы все ведра были заполнены, а не чтобы два ведра были заполнены на 150, а другое ведро только, скажем, 50


person Argho Chatterjee    schedule 06.10.2015    source источник
comment
Относится ли диапазон ведра к сумме, которая должна в нем содержаться, или это диапазон отдельных чисел в этом ведре?   -  person Tim Biegeleisen    schedule 06.10.2015
comment
Правильно ли я понял, что должны выполняться только ограничения (т. е. каждое ведро от 100 до 150; используются все элементы), но в остальном поиск наилучшего решения не требуется.   -  person Henry    schedule 06.10.2015
comment
Что вы пробовали? Какая у него производительность, или если не работала, то в каких условиях глючит? У вас есть код?   -  person Davislor    schedule 06.10.2015
comment
Эй, можете ли вы сказать, какое максимальное количество элементов и сегментов в вашей задаче?   -  person vish4071    schedule 06.10.2015
comment
Привет @TimBiegeleisen, это сумма чисел внутри ведра.   -  person Argho Chatterjee    schedule 06.10.2015
comment
Вы пытались смоделировать проблему как целочисленную программу, а затем использовать какой-либо решатель, чтобы посмотреть, как она работает?   -  person sve    schedule 06.10.2015
comment
Привет @Henry, да, вы правы в понимании ограничений, и нет необходимости искать лучшее решение, но если это тоже можно сделать, то хорошо и хорошо !!!!!   -  person Argho Chatterjee    schedule 06.10.2015
comment
Привет @Lorehead, у меня нет готового кода для этого, мой подход состоял в том, чтобы рассматривать это как проблему ранца с максимальным весом 150 (верхний предел диапазона), а затем распределять дополнительные элементы (числа) в те ведра, которые были МЕНЬШЕ 100 (скажем, X) из этих ведер, которые были БОЛЕЕ 100 (скажем, Y), таким образом, что X не падает ниже 100, а Y повышается до 100 или выше.! Но это не будет стандартный алгоритм или какой-то частный случай любого стандартного алгоритма решения задачи.   -  person Argho Chatterjee    schedule 06.10.2015
comment
привет @vish4071, максимальное количество элементов может быть любым, скажем, 50 элементов (50 чисел), а ведра также могут быть любыми, у нас 5 ведер, мы проверяем, существует ли решение для данного массива чисел и фиксированного количества ведер, выполнение всех ограничений   -  person Argho Chatterjee    schedule 06.10.2015
comment
@ArghoChatterjee, я просил максимальное число, так как это помогает понять, какую парадигму можно использовать.   -  person vish4071    schedule 06.10.2015
comment
Привет @vish4071, моя ошибка в понимании вашего вопроса, хорошо, так что максимальное число может быть меньше 150, что является не чем иным, как моим верхним пределом. Правильно ли я ответил на ваш вопрос.   -  person Argho Chatterjee    schedule 06.10.2015
comment
Привет всем, можно ли решить эту проблему? Из нескольких моих колледжей я узнал, что это NP-полная проблема, и для ее решения нет эффективного алгоритма, да, это вариант проблемы рюкзака. Поэтому было рекомендовано использовать вместо этого простые эвристики. Может ли кто-нибудь прокомментировать, правда ли это, с вашим опытом и пониманием проблемы?   -  person Argho Chatterjee    schedule 06.10.2015


Ответы (2)


Одним из подходов было бы смоделировать это как целочисленную программу. Предположим, что есть "m" чисел y_1, y_2,..., y_m и "n" сегментов. Определите переменные x_ij с индексом «i» для каждого из чисел, которые вы пытаетесь присвоить, и индексом «j» для каждого сегмента. Это двоичные переменные, указывающие, присвоено ли каждому сегменту каждое число.

Теперь у вас есть два набора логических ограничений. Во-первых, вам нужно присвоить каждый номер ровно одному ведру. Вы можете сделать это, добавив следующее ограничение для каждого числа «i»:

x_i1 + x_i2 + ... + x_in = 1

У вас также есть ограничения диапазона для каждого сегмента "j":

100 <= y_1 x_1j + y_2 x_2j + ... + y_m x_mj <= 150

На самом деле вы просто ищете любые осуществимые решения, поэтому вы можете просто установить цель на 0 и рассматривать это как проблему осуществимости.

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

Чтобы дать представление о масштабируемости, рассмотрим следующую реализацию с использованием пакета lpSolve в R; он возвращает назначения из чисел в сегменты, когда существует допустимое назначение, и в противном случае возвращает вектор значений NA:

library(lpSolve)
range.assign <- function(weights, n, min.sum, max.sum) {
  m <- length(weights)
  one.mat <- t(sapply(1:m, function(i) c(replicate(n, 1*((1:m) == i)))))
  w.mat <- t(sapply(1:n, function(j) c(rep(0, m*(j-1)), weights, rep(0, m*(n-j)))))
  mod <- lp(objective.in = rep(0, n*m),
            const.mat = rbind(one.mat, w.mat, w.mat),
            const.dir = rep(c("=", ">=", "<="), c(m, n, n)),
            const.rhs = rep(c(1, min.sum, max.sum), c(m, n, n)),
            all.bin=TRUE)
  if (mod$status == 0) {
    apply(matrix(mod$solution, nrow=m), 1, function(x) which(x >= 0.999))
  } else {
    rep(NA, m)
  }
}
range.assign(1:5, 2, 5, 10)
# [1] 1 1 1 1 2
range.assign(1:5, 2, 5, 6)
# [1] NA NA NA NA NA

Я протестировал это с m весами, выбранными случайным образом из [1, 2, ..., 10], допустимым диапазоном для корзины [100, 150] и общим количеством корзин n = ceiling(5.5*m / 125). Я увидел следующее масштабирование во время выполнения:

  • m = 100, n = 5: 0,1 секунды
  • m = 200, n = 9: 0,6 секунды
  • m = 300, n = 14: 2,2 секунды
  • m = 400, n = 18: 16,9 секунды

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

  1. Использование коммерческих решателей, таких как Gurobi или cplex (оба платные в целом, но бесплатны для академического использования).
  2. Ввод матрицы ограничений в разреженном формате.
person josliber♦    schedule 06.10.2015
comment
эй @Josiber, я пытаюсь реализовать это на java, если вы можете предоставить какой-либо код sudo или ссылку на видеоурок вашей реализации, это действительно поможет, еще раз спасибо за ваши усилия.!!!! - person Argho Chatterjee; 10.10.2015
comment
@ArghoChatterjee Я бы посоветовал вам попробовать реализовать его самостоятельно и опубликовать новый вопрос, если у вас возникнут какие-либо проблемы с реализацией. - person josliber♦; 10.10.2015

Похоже на проблему k-разбиения, более известную как проблема с упаковкой в ​​bin. проблема NP-Complete, не будет «эффективного» решения. Однако, если вы посмотрите в Интернете, я уверен, что вы можете найти множество примеров кода, чтобы вы и ваши (*кашель*) "коллеги" могли решить эту проблему.

person Glubus    schedule 06.10.2015
comment
Я не верю, что классическая упаковка контейнеров поддерживает ненулевые нижние границы количества, назначенного каждому контейнеру, хотя, возможно, один из многих вариантов допускает эти ограничения. - person josliber♦; 06.10.2015
comment
привет @Glubus, я не понимаю, почему это простая проблема с разделами. Не могли бы вы объяснить больше об этом. Knapsap - это частный случай проблемы упаковки в корзину, если я не ошибаюсь, вы хотели предложить использовать Knapsap? Я уже реализовал его, но он не соответствует сценарию, упомянутому в вопросе. - person Argho Chatterjee; 06.10.2015
comment
Эй, Арго, по общему признанию, я не провел достаточно исследований, чтобы дать вам прямое решение вашей проблемы (в настоящее время я нахожусь на своей работе, поэтому я не могу вникнуть в нее). Однако я чувствую, что ваша проблема похожа на проблему упаковки в мусорное ведро, и я ожидаю, что вы сможете найти или создать свое решение, манипулируя некоторым существующим решением другой проблемы. Я рекомендую вам ознакомиться с проблемой/решениями различных проблем и выяснить, сможете ли вы найти решение своей проблемы. Если у меня будет время сегодня вечером, я попробую сам. - person Glubus; 06.10.2015
comment
Если вы чувствуете, что вам нужно решение быстрее, и вы не хотите читать статьи и тому подобное, взгляните на ответ @josilber, это другой подход, но моделирование вашей проблемы как целочисленной проблемы может сработать! - person Glubus; 06.10.2015