动态资源分配:根据成本优化将订单分配到仓库

问题描述 投票:0回答:1

我有3个仓库,分别命名为A、B、C,它们的最小订购量不同。每块板的每个订单都有最低成本。考虑到订单总数,我已将这些订单分配到每个仓库的至少一块板中,这样我总是选择成本最低的板。

例如:

Slab for warehouse  A :
A_1 = Minimum 400000 lakh order : 59.5 cps
A_2 = Minimum 500000 lakh order : 58.2 cps
A_3 = Minimum 770000 lakh order : 55.7 cps
A_4 = Minimum 1100000 lakh : 53.8 cps
A_5 = Minimum 1500000 lakh : 53.1 cps
 
 
Slab for warehouse B :
B_1 = Minimum 500000 lakh order : 63 cps
B_2 = Minimum 800000 lakh order : 59.4 cps
B_3 = Minimum 900000 lakh order : 56.5 cps
B_4 =Minimum 1200000 lakh : 53 cps
B_5 =Minimum 1500000 lakh : 52.5 cps
 
Slab for warehouse C :
C_1 =Minimum 1650000 lakh order : 54 cps
C_2 =Minimum 2000000 lakh order : 50 cps

如果我得到 300000 个订单,那么我不同仓库的最佳板坯组合将是 可以有不同的情况组合,其中给出 2 种情况的示例

Case 1:
warehouse C : minimum order 2000000 * 50 = 100000000 (if we select  C_2)
warehouse B :  minimum order 900000 * 56.5 = 50850000 (if we select  B_3)
warehouse A :  minimum order 100000 * 59.5 = 5950000 (if we select  A_1)

(100000000 + 50850000 + 5950000)/3000000 = 52.2666666667
Minimum cost for 300000 will be 52.2666666667

Case 2:
warehouse C : minimum order 2000000 * 50 = 100000000 (if we select  C_2)
warehouse B :  minimum order 130000 * 63 = 8190000 (if we select  B_1)
warehouse A :  minimum order 770000 * 55.7 = 42889000 (if we select  A_3)

(100000000 + 8190000 + 42889000 )/3000000 =50.3596666667
Minimum cost for 300000 will be 50.3596666667

在上述两种情况下,情况2的成本最小,所以我们将选择情况2作为分配。

这里的订单可以是任何数字,例如 6500000 或 8000000。

我尝试了这个,但输出不正确

slabs_A = [(400000, 59.5), (500000, 58.2), (770000, 55.7), (1100000, 53.8), (1500000, 53.1)]
slabs_B = [(500000, 63), (800000, 59.4), (900000, 56.5), (1200000, 53), (1500000, 52.5)]
slabs_C = [(1650000, 54), (2000000, 50)]

total_orders = 300000

allocation = {}
remaining_orders = total_orders

def get_min_cost_slab(slabs, remaining_orders):
    min_cost = float('inf')
    selected_slab = None
    for order, cost in slabs:
        if order <= remaining_orders and cost < min_cost:
            min_cost = cost
            selected_slab = order, cost
    return selected_slab

for slabs, warehouse in zip([slabs_A, slabs_B, slabs_C], ['A', 'B', 'C']):
    selected_slab = get_min_cost_slab(slabs, remaining_orders)
    if selected_slab:
        allocation[(warehouse, selected_slab[0])] = selected_slab[1]
        remaining_orders -= selected_slab[0]

min_cost = sum(allocation.values())

print(f"Minimum cost for {total_orders} orders: {min_cost}")
print("Optimal Allocation:")
for (warehouse, slab), quantity in allocation.items():
    print(f"Warehouse {warehouse}, Slab {warehouse}_{slab}, Quantity: {quantity}")

预期输出如下

Warehouse A, Slab A_3, Quantity: 770000, cost : 770000 * 55.7 = 42889000
Warehouse B, Slab B_1, Quantity:130000, cost : 130000 * 63 = 8190000
Warehouse C, Slab C_2, Quantity:200000, 2000000 * 50 = 100000000
Total cost : (100000000 + 8190000 + 42889000 )/3000000 =50.3596666667
python algorithm optimization combinations
1个回答
0
投票

我知道您正在寻找 Python 解决方案,但由于问题发布几个小时后还没有发布任何解决方案,我将提供 Ruby 版本的解决方案,它可以被视为伪代码,我相信可以轻松地将其转换为 Python .


我们得到以下数据。

total = 3_000_000
warehouses = {
  :A => {
    :A_1 => { :capacity =>   400_000, :cost => 59.5 },  
    :A_2 => { :capacity =>   500_000, :cost => 58.2 },
    :A_3 => { :capacity =>   770_000, :cost => 55.7 },
    :A_4 => { :capacity => 1_100_000, :cost => 53.8 },
    :A_5 => { :capacity => 1_500_000, :cost => 53.1 }
  },
  :B => {
    :B_1 => { :capacity =>   500_000, :cost => 63.0 },
    :B_2 => { :capacity =>   800_000, :cost => 59.4 },
    :B_3 => { :capacity =>   900_000, :cost => 56.5 },
    :B_4 => { :capacity => 1_200_000, :cost => 53.0 },
    :B_5 => { :capacity => 1_500_000, :cost => 52.5 }
  },
  :C => {
    :C_1 => { :capacity => 1_650_000, :cost => 54.0 },
    :C_2 => { :capacity => 2_000_000, :cost => 50.0 }
  }
}

可以使用以下 Ruby 方法(我将对其进行解释)。

def minimum_cost_allocation(warehouses, tot)
  a = warehouses.map { |k,v| v.to_a }
  a.shift
   .product(*a)
   .select { |arr| sufficient_capacity?(arr, tot) }
   .min_by do |combo|
     cost(combo.permutation(combo.size).min_by { |perm| cost(perm, tot) }, tot)
    end  
end
def sufficient_capacity?(arr, total)
  arr.sum { |_lbl, h| h[:capacity] } >= tot
end
def cost(arr, tot)
  arr.sum do |_lbl,h|
    f = [tot, h[:capacity]].min
    tot -= f
    f * h[:cost]
  end
end

我们现在可以计算上述数据的平板的最小成本分配。

minimum_cost_allocation(warehouses, total) 
  #=> [[:A_1, {:capacity=>400000, :cost=>59.5}],
  #    [:B_5, {:capacity=>1500000, :cost=>52.5}],
  #    [:C_2, {:capacity=>2000000, :cost=>50.0}]]

最低成本

cost(minimum_cost_allocation(warehouses, total), total)
  #=> 157550000.0

可以根据

minimum_cost_allocation
的返回值和方法
cost
轻松构建所需的结果格式。


参见方法 Array#mapArray#shiftArray#productArray#selectEnumerable#min_byArray#permutationArray#sumHash#[] .


对于方法

sufficient_capacity?
if

arr1 = [[:A_5, {:capacity=>1500000, :cost=>53.1}],
        [:B_5, {:capacity=>1500000, :cost=>52.5}],
        [:C_1, {:capacity=>1650000, :cost=>54.0}]]

然后

sufficient_capacity?(arr1, total)
  #=> true

但是,如果

arr2 = [[:A_1, {:capacity=> 400000, :cost=>59.5}],
        [:B_1, {:capacity=> 500000, :cost=>63.0}],
        [:C_1, {:capacity=>1650000, :cost=>54.0}]]

然后

sufficient_capacity?(arr, total)
  #=> false

对于方法

cost

cost(arr1, total)
  #=> 158400000.0

这等于 `53.1 * 1_500_000 + 52.5 * 1_500_000 + 54.0 * 0 = 158_400_000.0

其中 `3_000_000 - 1_500_000 - 1_500_000 = 0


计算步骤如下。

a = warehouses.map { |_k,v| v.to_a }
  #=> [[[:A_1, {:capacity=>400000, :cost=>59.5}],
  #     [:A_2, {:capacity=>500000, :cost=>58.2}],
  #     [:A_3, {:capacity=>770000, :cost=>55.7}],
  #     [:A_4, {:capacity=>1100000, :cost=>53.8}],
  #     [:A_5, {:capacity=>1500000, :cost=>53.1}]],
  #    [[:B_1, {:capacity=>500000, :cost=>63.0}],
  #     [:B_2, {:capacity=>800000, :cost=>59.4}],
  #     [:B_3, {:capacity=>900000, :cost=>56.5}],
  #     [:B_4, {:capacity=>1200000, :cost=>53.0}],
  #     [:B_5, {:capacity=>1500000, :cost=>52.5}]],
  #    [[:C_1, {:capacity=>1650000, :cost=>54.0}],
  #     [:C_2, {:capacity=>2000000, :cost=>50.0}]]]
b = a.shift
  #=> [[:A_1, {:capacity=>400000, :cost=>59.5}],
  #     ...
  #    [:A_5, {:capacity=>1500000, :cost=>53.1}]]
a
  #=> [[[:B_1, {:capacity=>500000, :cost=>63.0}],
  #     ...
  #     [:B_5, {:capacity=>1500000, :cost=>52.5}]],
  #    [[:C_1, {:capacity=>1650000, :cost=>54.0}],
  #     [:C_2, {:capacity=>2000000, :cost=>50.0}]]]
c = b.product(*a)
  #=> [[[:A_1, {:capacity=>400000, :cost=>59.5}],
  #     [:B_1, {:capacity=>500000, :cost=>63.0}],
  #     [:C_1, {:capacity=>1650000, :cost=>54.0}]],
  #    [[:A_1, {:capacity=>400000, :cost=>59.5}],
  #     [:B_1, {:capacity=>500000, :cost=>63.0}],
  #     [:C_2, {:capacity=>2000000, :cost=>50.0}]],
  #      ...
  #    [[:A_5, {:capacity=>1500000, :cost=>53.1}],
  #     [:B_5, {:capacity=>1500000, :cost=>52.5}],
  #     [:C_1, {:capacity=>1650000, :cost=>54.0}]],
  #    [[:A_5, {:capacity=>1500000, :cost=>53.1}],
  #     [:B_5, {:capacity=>1500000, :cost=>52.5}],
  #     [:C_2, {:capacity=>2000000, :cost=>50.0}]]]
c.size
  #=> 50

c
包含所有大小为 3 的数组,其中第一个元素取自
a[0]
,第二个取自
a[1]
,第三个取自
a[2]
。有
b.product(*a).size #=> 50
个元素,等于
a[0].size*a[1].size*a[2].size #=> 5*5*2

d = c.select { |arr| sufficient_capacity(arr, tot) }
  #=> [[[:A_1, {:capacity=>400000, :cost=>59.5}],
  #     [:B_2, {:capacity=>800000, :cost=>59.4}],
  #     [:C_2, {:capacity=>2000000, :cost=>50.0}]],
  #      ...
  #    [[:A_5, {:capacity=>1500000, :cost=>53.1}],
  #     [:B_5, {:capacity=>1500000, :cost=>52.5}],
  #     [:C_2, {:capacity=>2000000, :cost=>50.0}]]]
d.size
  #=> 43

d
c
(不可行)元素中删除其组合容量小于
total
的元素。

我们现在必须检查

3x2 #=> 6
中每个数组的所有
d
排列。对于每个排列
perm
,我将首先将库存分配给板坯
perm[0]
,然后是
perm[1]
,然后是
perm[2]
,观察板坯产能。
43*6 #=> 258
因此必须计算组合的成本。

d.min_by do |combo|
  best = combo.permutation(combo.size).min_by { |perm| cost(perm, tot) }
  puts "for combo = #{combo}\nbest = #{best}"
  cst = cost(best, tot)
  puts "cost of best = #{cst}"
  cst
end
  #=> [[:A_1, {:capacity=>400000, :cost=>59.5}],
  #    [:B_5, {:capacity=>1500000, :cost=>52.5}],
  #    [:C_2, {:capacity=>2000000, :cost=>50.0}]]

显示以下内容。

  for combo = [[:A_1, {:capacity=>400000, :cost=>59.5}],
               [:B_2, {:capacity=>800000, :cost=>59.4}],
               [:C_2, {:capacity=>2000000, :cost=>50.0}]]
       best = [[:B_2, {:capacity=>800000, :cost=>59.4}],
               [:C_2, {:capacity=>2000000, :cost=>50.0}],
               [:A_1, {:capacity=>400000, :cost=>59.5}]]
    cost of best = 159420000.0
  for combo = [[:A_1, {:capacity=>400000, :cost=>59.5}],
               [:B_3, {:capacity=>900000, :cost=>56.5}],
               [:C_2, {:capacity=>2000000, :cost=>50.0}]]
       best = [[:B_3, {:capacity=>900000, :cost=>56.5}],
               [:C_2, {:capacity=>2000000, :cost=>50.0}],
               [:A_1, {:capacity=>400000, :cost=>59.5}]]
    cost of best = 156800000.0
    ...
  for combo = [[:A_5, {:capacity=>1500000, :cost=>53.1}],
               [:B_5, {:capacity=>1500000, :cost=>52.5}],
               [:C_2, {:capacity=>2000000, :cost=>50.0}]]
       best = [[:C_2, {:capacity=>2000000, :cost=>50.0}],
               [:B_5, {:capacity=>1500000, :cost=>52.5}],
               [:A_5, {:capacity=>1500000, :cost=>53.1}]]
    cost of best = 152500000.0
© www.soinside.com 2019 - 2024. All rights reserved.