0

私たちのウェブサイトは注文の配送合計を計算します。データベース内のすべてのアイテムには立方体のサイズがあり、アイテムの宅配便と貨物の使用にはサイズ制限があります. しかし、私たちは複数のアイテムを注文しており、必要のないときに貨物を呼んでいることに気付きました.

小包の制限は、宅配便チケットあたり 0.15 m3 です。それよりも大きい場合は、代わりに貨物を使用する必要があります。ちなみに、最小料金があるからといって、小口貨物の場合は運賃が高くなりますが、なくてもまったく問題ありません。

私たちのプログラマーが国を出るまでの時間が限られているため、ここで質問しています。これは私たちが彼に与えた緊急のタスクの 1 つではありませんでした。もしそれをやり遂げるなら、私は彼が正しい方向に進むのを助ける必要があります -残念ながら、私はプログラマーではありません。

問題:
注文が 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 ドル) を送信できます。

これを行うことができますか: 1 つのアイテムが 0.15 より大きい場合は、すべて貨物にします。そうでない場合は、可能な限り大きな箱に梱包したと仮定して、必要なチケットの数を合計します 例 2:

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

トリッキーなことはわかっていますが、それは単なる数学です笑、そしてそれは最も重要なことです。

4

2 に答える 2

2

@AlistairIsraelが言ったように、これは解決するのが完全に簡単ではないビンパッキングの問題です。

ただし、以下はこの問題に対する 1 つの解決策です。

アイテムをパッケージ化する方法のすべての組み合わせを検討し、最小限のコストを見つけようとすれば、解決策があります. このソリューションはブルート フォース ソリューションであるため、アイテムの数が増えるとすぐに遅くなることに注意してください。

貨物を異なる箱に分割する方法をすべて見つける。そのために、この回答のアルゴリズムを使用できます。

Python から 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
于 2013-06-21T04:55:32.180 に答える
0

コードは示されていませんが、基本的に、配列などのコレクションである注文を受け取り、次のようにします。

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

もちろん、さらに多くのロジックが必要になりますが、必要な作業を続行するために、貨物をブール値として true または false として使用できるようになりました。

countここでもあなたの友達になると思います。

于 2013-06-21T03:56:13.823 に答える