复杂的运费计算

时间:2013-06-21 03:13:10

标签: ruby-on-rails ruby shipping

我们的网站列出了订单的运费总额,我们数据库中的每个项目都有一个立方大小,并且对于项目使用快递与运费有一个大小限制。但是我们收到了多件物品的订单,我注意到它在不需要时会收货。

每个快递票的包裹限额为0.15立方米,如果超过他们必须通过运费去。顺便提一下,小货物的运费成本更高,只是因为有最低费用,如果没有,这根本不会成为问题。

我在这里问,因为我们的程序员在他离开这个国家之前的时间有限,这不是我们给他的紧急任务之一,如果我们要完成它,那么我需要帮助他正确的方向 - 但是,我不是程序员。

问题:
订单包含2个项目,每个项目均为0.106到本地地址

  • 网站总共称它为0.212,运费为@ $ 42
  • 我们可以快递2箱,总共10美元

但如果任何一项超过0.15的限制,则只需使用运费 所以,它会看到订单为(0.106 = $ 5)和(0.106 = $ 5)= $ 10

例如:

  1. 假设有更复杂的事情:
    购物车中有10件商品,每件0.02件。网站将以0.2计算并称之为运费,但我们可以将其放入2个盒子并支付10美元

  2. 购物车中的5件商品,0.01 x 4和0.12 x 1.网站将以0.16的价格计算并称之为运费,但我们可以发送2个纸箱 - 0.04和0.12成本为10美元

  3. 它能做到这一点:如果任何一件物品大于0.15,那就全部运费,否则加起来需要多少票,假设我们把它装进最大的箱子里面 例2:

    (0.01+0.01+0.01+0.01)=0.04=$5,
    (0.12)=0.12=$5 
    ==$10
    

    我知道很棘手,但它只是数学大声笑,而且最重要的是因为一个荒谬的运费可能会停止订单。

2 个答案:

答案 0 :(得分:2)

就像@AlistairIsrael所说的那样bin packing problem并不是完全无关紧要的。

然而,以下是此问题的一种解决方案。

如果我们通过各种方式组合物品并尝试找到最低成本,那么我们就有了解决方案。请注意,此解决方案是一种强力解决方案,因此随着项目数量的增长而迅速减慢。

找到将货件分成不同方块的所有可能方法;我们可以使用这个答案的算法:

Translating function for finding all partitions of a set from Python to Ruby

接下来,我们遍历所有不同的组合并搜索最低成本。然后解决方案就像这样:

> optimize_shipping([0.01, 0.01, 0.01, 0.01, 0.12])
Shipping type: courier
Total price  : $10
Packaging    : [[0.12], [0.01, 0.01, 0.01, 0.01]]

> optimize_shipping([0.01, 0.01, 0.12, 0.15, 0.12])
Shipping type: courier
Total price  : $15
Packaging    : [[0.01, 0.12], [0.15], [0.01, 0.12]]

> optimize_shipping([0.09, 0.09, 0.01, 0.12, 0.15, 0.12])
Shipping type: courier
Total price  : $25
Packaging    : [[0.12], [0.15], [0.12], [0.09, 0.01], [0.09]]

> optimize_shipping([0.01, 0.01, 0.01, 0.30])
Shipping type: freight

代码:

COURIER_LIMIT = 0.15
COURIER_PRICE = 5

class Array
  def sum
    inject(:+)
  end

  def partitions
    yield [] if self.empty?
    (0 ... 2 ** self.size / 2).each do |i|
      parts = [[], []]
      self.each do |item|
        parts[i & 1] << item
        i >>= 1
      end
      parts[1].partitions do |b|
        result = [parts[0]] + b
        result = result.reject do |e|
          e.empty?
        end
        yield result
      end
    end
  end
end

def optimize_shipping(boxes)
  if boxes.any? { |b| b > COURIER_LIMIT }
    puts "Shipping type: freight"
    return
  end

  # Try and find the cheapest most optimal combination of packaging
  smallest_box   = 9999
  cheapest_price = 9999
  cheapest_combination = []

  # Go through all paritions and find the optimal distribution
  boxes.partitions { |partition|
    # Add up sizes per box
    sizes = partition.map(&:sum)

    # Check if any box got too big for courier, and skip if so
    next if sizes.any? { |s| s > COURIER_LIMIT }

    # Calculate total price for this combination
    total_price = partition.length * COURIER_PRICE

    if total_price <= cheapest_price
      # Naive algo to try and find best average distriution of items
      next if total_price == cheapest_price && sizes.min < smallest_box

      # Save this new optimized shipment
      smallest_box         = sizes.min
      cheapest_price       = total_price
      cheapest_combination = partition
    end
  }

  puts "Shipping type: courier"
  puts "Total price  : $#{cheapest_price}"
  puts "Packaging    : #{cheapest_combination.inspect}"
end

答案 1 :(得分:0)

没有显示代码,但基本上,您可以接受可能是数组等集合的订单,并执行以下操作:

orders = [0.01,0.16,0.01,0.01]
freight = orders.any? {|item| item > 0.15 }

当然,需要更多逻辑,但您现在可以使用true或false作为布尔值来继续进行所需的工作。

我相信count也会成为你的朋友。