我有一个问题涉及游戏中的齿轮优化,但我会用这个例子简化它:
我希望最大限度地提高所有行李的价格,但我有以下限制:
项目数量范围为200~300,并且6 * 4 = 24个最大项目可以选择,不可能暴力。
还有其他因素,但这些因素超出了组合问题,可以通过简单的编程来解决
<小时/> 我调查了一下,现在我知道这是一个多维或多选背包问题。解决了简单的背包问题,现在我只剩1个约束,6个项目限制。
任何人都知道对此有好处吗?
<小时/> 我现在正在使用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
函数在那里不起作用。我试过这个公式
(无法发布图片)
但我也不能使用abs功能。
有人可以指出我正确的方向。
答案 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,禁忌搜索,群体。