具有多个约束的组合优化

时间:2015-12-12 22:43:34

标签: linear-programming knapsack-problem ampl glpk

我有一个问题涉及游戏中的齿轮优化,但我会用这个例子简化它:

  • 假设我有4个包。
  • 我有一组不同的项目,有4种类型。
  • 每件商品都有其重量和价格。
  • 每个袋子适用于一种物品,4袋--4种类型。


我希望最大限度地提高所有行李的价格,但我有以下限制:

  1. 每个包最多可容纳6件物品。它也可以是空的。
  2. 所有4个袋子的总重量不得超过700公斤。
  3. 每个袋子都有一个最小重量值,即使它是空的,也算50kg(一件25kg的袋子仍然算作50kg,一件51kg的袋子算作51kg)。
  4. 项目数量范围为200~300,并且6 * 4 = 24个最大项目可以选择,不可能暴力。

    还有其他因素,但这些因素超出了组合问题,可以通过简单的编程来解决


    这有什么问题?它是线性规划的子集吗?
    你知道我可以通过什么样的算法来解决这个问题吗?

    我开始阅读有关线性编程的内容,但我在理解某些符号时遇到了问题。我有编程经验但不涉及数学。

    更新

    <小时/> 我调查了一下,现在我知道这是一个多维或多选背包问题。解决了简单的背包问题,现在我只剩1个约束,6个项目限制。

    任何人都知道对此有好处吗?

    更新2

    <小时/> 我现在正在使用GLPK来解决这个问题并解决它,我已经接近完成了它,但我仍然坚持一个简单的约束。

    # Size of knapsack
    param s;
    # Total of items
    param t;
    # Type of items
    set Z;
    # Min bag
    param m;
    
    # Items: index, size, profit, count, type
    set I, dimen 5;
    
    # Indices
    set J := setof{(i,s,p,o,z) in I} i;
    
    # Assignment
    var a{J}, binary;
    
    #maximize profit
    maximize obj :
      sum{(i,s,p,o,z) in I} p*a[i];
    
    /*s.t. size :
      sum{(i,s,p,o,z) in I} s*a[i] <= c;*/
    
    #constraint of total weight, but with the min value for each bag
    #the min function doesn't work, it says argument for min has invalid type
    #something about it not being a linear function
    s.t. size :
      sum{zz in Z} ( 
        min(m, sum{(i,s,p,o,z) in I: zz=z} (s*a[i]) )
      ) <= c;
    
    #constraint of number of items in each bag, i put an extra count number
    #in the set so i could sum it and make it a constraint
    s.t. count{zz in Z}:
      sum{(i,s,p,o,z) in I: zz=z} o*a[i] <= t;
    
    solve;
    
    printf "The bag contains:\n";
    printf {(i,s,p,o,z) in I: a[i] == 1} " %i", i;
    printf "\n";
    
    data;
    
    #set of type of items
    set Z := 1 2 3 4;
    
    # Total weight limit
    param c := 100;
    # Only 2 items per bag
    param t := 2;
    # Min bag value, if the bag weights less than it, then it counts as this value
    param M := 10;
    
    # Items: index, size, profit, count, type
    set I :=
      1 10 10 1 1 
      2 10 10 1 1
      3 15 45 1 2
      4 20 20 1 2
      5 20 20 1 3
      6 24 24 1 3
      7 24 25 1 4
      8 50 50 1 4;
    
    end;
    

    注意:我在这里使用不同的值来保持它的小。

    这是我的模型,它在没有最小重量约束的情况下工作,我只需要将50kg的最小值或包总数加起来,但min函数在那里不起作用。我试过这个公式

    (无法发布图片)

    min(a,b) = (a+b- abs(a-b))/2

    但我也不能使用abs功能。

    有人可以指出我正确的方向。

3 个答案:

答案 0 :(得分:2)

您可以将问题表示为0-1整数程序,并使用GLPK或其他线性编程求解器解决它(glpk是免费的)。唯一的问题是:你带空袋子吗? 让

i = {1,2,3,4} -- set of item types
j -- set of items
x_ij = {0,1} -- decision variable for jth item of ith type
w_ij and p_ij -- weights and profits

max sum_ij p_ij*x_ij

subject to:
sum_j x_ij <= 6 for all i  // at most 6 items in a bag
// if you need empty bags:
sum_ij w_ij*x_ij + 4*50 <= 700 kg  // total weight

x_ij = {0,1} for all i and j.

如果你不需要空袋,那么配方会变得更加复杂

max sum_ij p_ij*x_ij

subject to:
sum_j x_ij <= 6    for all i  // at most 6 items in a bag
sum_ij w_ij*x_ij + 50*(sum_i y_i) <= 700 kg  // total weight
y_i <= sum_j x_ij    for all i  
N*y_i >= sum_j x_ij    for all i  // N -- total number of items of ith type, 
                                  // fixed value, not a variable; e.g., 
                                  // you have 10 items of each kind then N=10

y_i = {0,1} for all i
x_ij = {0,1} for all i and j.

如果你需要解决一次程序,那么我建议写一个cplex .lp文件http://www-01.ibm.com/support/knowledgecenter/SS9UKU_12.4.0/com.ibm.cplex.zos.help/FileFormats/topics/LP.html并用glpsolve解决它;否则使用c ++或python glpk可调用库。

更新1:

可以分两步线性化约束min{50, sum_i x_i*w_i}。为简单起见,考虑一个背包。让

M -- the total possible weight (sum up all input items' weights)
y={0,1} -- when sum_i x_i*w_i >= 50 y=1, otherwise y=0

min{50, sum_i x_i*w_i} <= 100    is equivalent to
(0): (1-y)*50 + y*(sum_i x_i*w_i) <= 100
(1): My >= sum_i x_i*w_i - 50
(2): M(1-y) >= 50 - sum_i x_i*w_i

这有点不寻常,但这是正确的。实际上,当sum_i x_i*w_i >= 50解算器必须通过约束y(1)设置为1时,(2)只是0 >= 50-sum_i x_i*w_i <= 0,即是多余的;当sum_i x_i*w_i < 50时,(2)的y = 0,现在(1)是多余的。

下一步是在(0)中线性化第二个词。设z_i = {0,1},它将代表y*x_i字词。请注意,y*x_i仅在两个术语均为1时为1,否则为0.因此,

y*(sum_i x_i*w_i)  is equivalent to

sum_i z_i*w_i
2*z_i <= x_i + y,  for all i
z_i >= x_i + y - 1,  for all i
和以前一样,只有当x_i = y = 1时才能检查z_i = 1,否则就是0。

线性化后,您的约束如下所示:

(0): (1-y)*50 + (sum_i z_i*w_i) <= 100

(1): My >= sum_i x_i*w_i - 50
(2): M(1-y) >= 50 - sum_i x_i*w_i

(3): 2*z_i <= x_i + y,  for all i
(4): z_i >= x_i + y - 1,  for all i

 y = {0,1}, z_i = {0,1}

答案 1 :(得分:1)

为了处理50公斤袋子的限制,你必须为每个袋子的重量创建一个变量,W_j

W_j >= 50  for all j
W_j >= sum_i w_i * X_ij for all j
sum_j W_j <= 700

这样袋子的重量总是至少50公斤,但如果物品的重量超过50公斤(根据您的问题定义),则更多。

祝你好运:)

答案 2 :(得分:0)

如果您正在寻找一个确切的最佳答案,那么问题就是NP完成,但是,我注意到您描述了一个非常小的问题集。

如果您的问题是小型的强力搜索是可行的:您可以生成所有可能的解决方案,计算解决方案成本,并选择最佳解决方案。

如果您的示例只是概述了一个问题描述,而您的现实生活中的问题集实际上是大型的,那么蛮力不会起作用,因为执行时间将呈指数级增长与项目数量。这是一个相当old paper on this problem

一个有趣的通知是,you can transform your constraints into numerical&#34;惩罚&#34;并使用无约束优化技术,简化您的问题。

保证最佳解决方案的算法仍然需要启发式修剪不良/不可行和&#34;支配&#34;解决方案很快。

根据我读过的研究,即使使用修剪启发式方法,这种方法实际上不可能超过相对较小的一组"paper about 2 phase" approach

典型的元启发式优化技术适用于较大的集合,特别是Simulated Annealing,禁忌搜索,群体。