一種方法是將它建模爲一個整數程序。假設有「m」個數字y_1,y_2,...,y_m和「n」個桶。定義變量x_ij,對於您要分配的每個數字,索引「i」和每個存儲桶的索引「j」。這些是二進制變量,指示每個數字是否分配給每個存儲桶。
現在你有兩套邏輯約束。首先,您需要將每個號碼分配給一個存儲桶。您可以通過添加以下約束每個號碼「我」這樣做:
x_i1 + x_i2 + ... + x_in = 1
您也有關於每個桶「J」的範圍限制:
100 <= y_1 x_1j + y_2 x_2j + ... + y_m x_mj <= 150
真的你只是在尋找任何可行的解決方案,因此您可以將目標設置爲0並將其視爲可行性問題。
當你解決一個NP完全問題,所以這是一個理論上具有挑戰性的練習,你可能會發現現代優化軟件可以解決你感興趣的問題大小的問題。
要了解可擴展性,請考慮使用R中的lpSolve
軟件包進行以下實現:
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]
,和總數測試這樣的:當一個有效的賦值存在,否則返回NA值的矢量,它返回從數字到桶中的分配的水桶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秒
似乎問題可以用十幾個桶和幾百個權重(以及這個權向量結構)的問題完全使用自由解算器來解決。當然,你的複雜性結果表明它不能有效地解決巨大的問題,但你可能能夠解決你感興趣的大小的實例。進一步優化可以通過以下方式進行:
- 使用商業求解器,如Gurobi或cplex(兩者都是非免費的,但一般免費供學術使用)。
- 以稀疏格式輸入約束矩陣。
桶範圍是指必須包含在其中的總和還是該桶中單個數字的範圍? –
我是否明白只有約束必須被滿足(即每個桶在100到150之間;所有使用的元素),但是沒有必要找到「最佳」解決方案。 – Henry
你有什麼嘗試?它的性能如何,或者它不起作用,在什麼情況下它是越野車?你有代碼嗎? – Davislor