将数字组合成不超过最大值向量的最优组的算法?

时间:2013-08-03 20:26:28

标签: r grouping mathematical-optimization

我正在为我的房子切割装饰件,并且有各种长度的装饰件,并且希望将它们最佳地分组以获得最小量的废料。基本上,我试图将所需的长度最佳分组(或打包)到可用的更长的长度。

我对如何处理这个问题感到有点困惑,而且目前只是手工操作,但最终导致我重新完成整个操作。我知道一些java,但最近一直在与R一起工作,所以这是我最熟悉的语言。有关于如何处理此问题的建议吗?

有没有更好的方法来做这个比使用这样的算法手动循环(我只是勾画这个想法;不要寻找正确的语法):

trim_lengths <- c(44, 57, 86, 86, 40, 88, 88, 41, 40, 40,
  62, 62, 54, 54, 55, 55, 63, 63, 75, 75, 100, 100)

avail_lengths <- c(120, 103, rep(100, 9), 98, rep(97, 4),
  95, rep(88, 3), 85, 65)

while(length(trim_lengths) > 0) {
  current_max <- max(trim_lengths)
  current_min <- min(trim_lengths)

  if(current_max + current_min > max(avail_lengths) {
    find smallest value in avail_lengths that's greater than current_max
    store current_max and optimal value from avail_lengths in list or vector
      to indicate the pairing/grouping
  }

  else {
    group <- c(current_max, current_min)
    current_max <- trim_lengths minux elements in group
    if <- sum(group) + current_max > max(avail_lengths) {
      store group and corresponding avail_length element in list/vector
    }

    else{
      basically, keep trying to group until solved
    }
  }

我已经知道这不是最优的,因为它是从trim_lengths向量的“outside in”进行检查,而我的手工完成配对通常最终会将中小型值配对到可用长度非常漂亮容易看到的只比所述配对长一两英寸。

无论如何,这是一个有趣的问题,我想知道是否有一些参考或明显的建议可以想到一个解决方案。在一些相关问题中,第一条评论经常会问:“你做了什么?”我真的没有...因为我现在很难过。我想到的唯一另一件事是随机强制组合,存储最小化浪费的解决方案。

我喜欢以矢量化的方式解决这个问题的一些建议 - 某种矩阵运算,或者可能是问题的线性模型表示。我会继续考虑它。

4 个答案:

答案 0 :(得分:3)

这个multiple-knapsack问题似乎很有趣,尝试使用lpSolveAPI,这就是我所做的。我使用整数编程方法找到修剪问题的最佳解决方案。

首先,我发现的解决方案如下:

enter image description here

正如您所看到的,根本不需要5件可用件。 (100%盈余)

<强>配方

  • 让a_1,a_2,...,a_k成为可用的篇幅。
  • 设t_1,t_2,...,t_n为所需的修剪长度。

  • 变量: 如果从可用的片段 t 中剪切 t ,则让X_a_t为1,否则为

将Surplus_i定义为A_i减去j = 1..n(X_a_t * t_j)的总和

  • 目标:尽量减少所有A(1..k)
  • 的Surplus_i总和

<强>约束

  • 设置分区约束:(英文)必须从某个部分剪切每个剪裁

      Sum over A(1..k) X_a_t = 1 for all t (1..n)
    

此外,所有盈余都必须是&gt; = 0#禁止否定

A_i - sum over j in 1..k X_ai_tj * t_j  = Surplus_i (for each Ai) # definitional constraint.

使用lpSolveAPI的R代码

在我的A矩阵中(第一组列是剩余变量,下一组是X_a_t变量。 第一组约束是“集合覆盖”约束。 第二组约束是“剩余”非负性约束。 检查trimIP.lp文件以查看完整的配方。

警告:代码比我想要的要长,但现在是:

library(lpSolveAPI)

#Problem definition
trim.lengths <- c(44, 57, 86, 86, 40, 88, 88, 41, 40, 40, 62, 62, 54, 54, 55, 55, 63, 63, 75, 75, 100, 100)
avail.lengths <- c(120, 103, rep(100, 9), 98, rep(97, 4), 95, rep(88, 3), 85, 65)
num.trims = length(trim_lengths) #22
num.avail = length(avail.lengths) #22
a.set<-1:num.avail
t.set <- 1:num.trims

#set rownames & colnames
setRowAndColNames<- function() {  
  a.and.t<- t(outer(a.set, t.set, paste, sep="_"))
  col.names <- paste("x_", a.and.t, sep="")
  s.vars <- paste("Surplus_", a.set, sep="")
  c.names <- c(s.vars, col.names)
  r.names <- setRowNames() 
  return( list(r.names, c.names)  )
}

setRowNames <- function() {
  cover.rows<- paste("CoverTrim", t.set, sep="_") #Cover constraints
  surplus.rows <- paste("DefineSurplus", a.set, sep="_") #non-neg constraints
  r.names <- c(cover.rows, surplus.rows)
  return(r.names)
}

populate.Amatrix <- function() {  
  df <- data.frame(matrix(0, n.rows, n.cols))  #create a dataframe shell  
  for (row in 1:num.trims) {
    skip = num.avail #for the surplus variables
    cols <- seq(0, (num.trims*num.avail)-1, by=num.avail)    
    df[row, skip+cols+row] <- 1
  }
  print("Done with cover Trims Constraints")
  st.row <- num.trims+1
  end.row<- st.row+num.avail-1
  for (row in st.row:end.row) {
    surplus.column <- row - num.trims
    df[row,surplus.column] <- 1
    current.a <- surplus.column
    acols <- num.avail + ((current.a-1)*num.trims) + (1:num.trims)
    df[row,acols] <- trim.lengths

  }
  return(df)
}


defineIP <- function(lp) {
  obj.vector <- c(rep(1, num.avail), rep(0, num.avail*num.trims))
  set.objfn(lp, obj.vector ) #minimize surplusses
  set.constr.type(lp, rep("=", n.rows), 1:n.rows) 
  rhs.vector <- c(rep(1, num.avail), avail.lengths)
  set.rhs(lp, b=rhs.vector, constraints=1:n.rows) # assign rhs values   

  #Set all the columns at once
  for (col in 1:n.cols) {
    set.column(lp, col, df[ ,col])  
  }

  for (col in (num.avail+1):n.cols) {
    print(col)
    set.type(lp, col, "binary")      
  }

  #assemble it all
  dimnames(lp) <- setRowAndColNames()
  write.lp(lp, "trimIP.lp", "lp")#write it out
}


# actual problem definition
n.rows <- num.trims + num.avail
n.cols <- (num.avail+1) * num.trims  #the extra one is for surplus variables
df <- populate.Amatrix()

lptrim <- make.lp(nrow=n.rows, ncol=n.cols)
defineIP(lptrim)
lptrim
solve(lptrim)
sol <- get.variables(lptrim)
sol <- c(sol, trim.lengths)
sol.df <- data.frame(matrix(sol, nrow=24, ncol=22 , byrow=T)) #you can examine the solution data frame

如果您想重现整个练习,我将代码放置为github gist

答案 1 :(得分:2)

enter image description here 由{/ em> http://xkcd.com/287/

提供

(是的,这是一个评论,而不是一个答案。如果只有imgs可以在小的评论行中加载)

答案 2 :(得分:1)

在我看来更像是一维切割库存问题。看看http://en.wikipedia.org/wiki/Cutting_stock_problem 关于这个话题还有很多。

希望这会有所帮助。我只是喜欢它,当有人遇到实际问题时,他们正在做一些真实的事情,并且实际上想着如何解决他们的问题,而不是盲目地收费。强大的学习机会...只是不要太依赖技术错综复杂,你忘了真正做真正的工作!

答案 3 :(得分:0)

您是否考虑过使用遗传算法?