Для фиксированного числа контейнеров это можно сформулировать как задачу целочисленного линейного программирования.Если g
- это вектор из 10 номеров групп, а cap
- это емкость, т. Е. 80, то должно быть не менее k=ceiling(sum(g) / cap)
контейнеров и не более k=length(g)
.Таким образом, мы последовательно подбираем от минимального до максимального количества остановок контейнеров, как только мы подходим.В случае данных, показанных в задаче (см. Примечание в конце), требуется только одна итерация.
В задаче lp
есть двоичные переменные k по n, и если мы упорядочим их в матрице ak по n, то i, j-й равен 1, если i-й контейнер содержит элемент j, и 0 в противном случае.
Задача lp имеет k + n ограничений.Первые k ограничений ограничивают сумму каждого из k контейнеров cap
, а оставшиеся n
ограничения гарантируют, что каждый элемент может встречаться только в одном контейнере.
library(lpSolve)
stopifnot(all(g <= cap))
n <- length(g)
kmin <- ceiling(sum(g) / cap)
for(k in seq(kmin, n)) {
objective.in <- rep(1, k * n)
const.mat <- rbind(diag(k) %x% t(g), t(rep(1, k)) %x% diag(n))
const.dir <- c(rep("<=", k), rep("==", n))
const.rhs <- c(rep(cap, k), rep(1, n))
res <- lp("min", objective.in, const.mat, const.dir, const.rhs, all.bin = TRUE)
if (res$status == 0) break
}
# iterations
k - kmin + 1
## [1] 1
# solution - each col is an element, each row is a container
matrix(res$solution, k, byrow = TRUE)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 1 1 1 1 1 0 0 1 0 0
## [2,] 0 0 0 0 0 1 1 0 0 1
## [3,] 0 0 0 0 0 0 0 0 1 0
Примечание
Входные данные были такими:
Lines <- "Group 1: 20
Group 2: 5
Group 3: 15
Group 4: 10
Group 5: 12
Group 6: 26
Group 7: 41
Group 8: 15
Group 9: 69
Group 10: 9"
g <- read.table(text = Lines)$V3
cap <- 80