web-dev-qa-db-ja.com

特定のパッキング問題のDPアルゴリズムを探す

解決すべき次の問題があります。

長さdのフェリーと、その長さを保持するn台の車のリストが与えられた場合、2つの異なるレーン(それぞれ長さdを持つ)のリストに表示される順序で車をフェリーにロードする必要があります。長さdと車のリストを指定して、フェリーに積載できる車の最大数を出力するプログラムを作成します。

O(2 ^ cars)でバックトラッキングを行うのは非常に簡単です。左側に車をロードしてすべての可能性を試し、最大を保存して右側に車をロードし、同じ節約の最大を再度実行します。

しかし、動的プログラミングでこれを多項式時間に短縮できると感じています。私の直腸の感覚が本当かどうか見分ける方法は?

5
qiubit

可能なアプローチは次のとおりです。

次のことを前提としています。どちらかが実際に正しくないかどうかをお知らせください。どちらのレーンにも追加できない車に遭遇したらすぐに、フェリーへの車の追加を停止します(大きな車をスキップして、リストの後半にある小さな車を追加することはできません)。すべての車の長さの合計が2d未満であると仮定します。そうでない場合、これは前処理ステップで簡単に実行できます。また、dは整数値であり、すべての車のサイズであると考えます。

これから行うのは、0/1ナップザック問題を解決して、車のセットが両方の車線に収まるかどうかを確認することです。

ここで、ナップザックのサイズはd(実際には車線です)、アイテムのサイズは車のサイズ、アイテムに関連付けられた値は車のサイズです(つまり、1つの車線を可能な限り)。この0/1ナップザック問題を解決するには、次のウィキペディアWebページで概説されているDPアルゴリズムを使用できます。 http://en.wikipedia.org/wiki/Knapsack_problem#0.2F1_knapsack_problem (ウィキペディアのページが消えても答えが出るように、ここで再現します):

S1、car 1のサイズ、s2をcar2のサイズなどと呼びます(n台の車があると見なします)。

M [i、s]は、合計サイズがs以下の自動車(最初のi自動車)を使用してs以下で達成できる最大値になるように定義します。

M [i、s]は、次のように再帰的に定義できます。m[i、s] = m [i-1、s] if si> s \、(新しい車は現在のサイズ制限よりも長い)m [i、 s] = max(m [i-1、s]、\、m [i-1、s-si] + si)siがs以下の場合。

次に、m [n、d]を計算することで解を見つけることができます。

ナップザック問題の解の車の長さの合計をsと呼びます。すべての車の長さの合計-sがd以下の場合、ナップザック問題を解決するために検討されたすべての車がフェリーに適合します(一方の車線はナップザックソリューションの一部として選択されたすべての車線、もう一方の車線)残りです)。残りの車の長さの合計がdを超える場合、すべての車がフェリーに収まりません。車のリストから最後の車を削除し、ナップザック問題を再度解決します。選択されていない車の長さの合計がd未満になるまで、これを行います。

ナップザック問題を解くためのDPアルゴリズムの複雑さはO(nd)であり、最大でn回解く必要があります->複雑さO(n ^ 2d)

これがPythonでのソリューションのスケッチです:

def solveKnapsack(cars, lengthOfLane):
  m = [[0] * (lengthOfLane+1)]
  for s in cars:
    m.append([])
    for j in range(lengthOfLane+1):
      if s <= j:
        m[-1].append(max(m[-2][j],m[-2][j-s]+s))
      else:
        m[-1].append(m[-2][j])
  return max(m[-1])

def solveTwoLanes(cars, lengthOfLane):
  maxOneLane = solveKnapsack(cars, lengthOfLane)
  if sum(cars) - maxOneLane <= lengthOfLane:
    return len(cars)
  else:
    return solveTwoLanes(cars[:-1], lengthOfLane)


def main():
  # small example that should output 2.
  print solveTwoLanes([3,3,3,1],5)

if  __name__ =='__main__':main()
4
Renaud M.

これは複数のナップザック問題です。ミドルインミドルアルゴリズムで解くと、各「レーン」にO(2 ^(n/2))がかかります。

セット{1 ... n}をほぼ同じサイズの2つのセットAとBに分割する
Aの各サブセットの各セットのすべてのサブセットの重みと値を計算します

結合された重みがW未満になるように最大値のBのサブセットを見つける
これまでに見た最大の合計値を追跡する

詳細はこちら: http://en.wikipedia.org/wiki/Knapsack_problem#Meet-in-the-middle

0
dresden