3

我正在为我的房子切割装饰条,并且有各种长度的装饰件,并希望将它们进行最佳分组,以减少浪费。基本上,我正在尝试将所需的长度最佳地分组(或打包)到可用的较长长度中。

我对如何解决这个问题有点困惑,目前只是手工完成,但一个错误最终导致我重新进行整个操作。我知道一些 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矢量上的“外向内”检查,而我的手工配对通常最终将一个中小值配对成一个很容易看到的可用长度,只有一英寸或比所述配对长两个。

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

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

4

4 回答 4

3

在此处输入图像描述   http://xkcd.com/287/提供

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

于 2013-08-03T20:31:45.297 回答
3

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

首先,这是我找到的解决方案的样子:

在此处输入图像描述

如您所见,有 5 个可用部件根本不需要。(100% 盈余)

公式

  • 设 a_1, a_2, ..., a_k 为可用的片长。
  • 令 t_1, t_2, ..., t_n 为所需的修剪长度。

  • 变量:如果修剪t是从可用片a中切割出来的,则令 X_a_t 为 1 ,否则为 0

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

  • 目标:最小化所有 A (1..k) 的 Surplus_i 的总和

约束

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

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

此外,所有盈余必须 >= 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

于 2013-08-06T07:18:55.437 回答
1

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

希望这可以帮助。我只是喜欢有人遇到实际问题,他们正在做一些真正的事情,并且真正考虑如何解决他们的问题,而不是盲目地投入。巨大的学习机会......只是不要太沉迷于技术你也忘记了真正做真正的工作的错综复杂!

于 2013-08-04T20:50:42.000 回答
0

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

于 2013-08-04T21:12:45.170 回答