有界ナップザック問題を0/1ナップザック問題に変換する


12

目標が動的プログラミング(他のアプローチの代わり)を使用することであるという問題に出くわしました。スパンする距離と、異なる長さのケーブルのセットがあります。距離を正確にスパンするために必要なケーブルの最小数は何ですか?

私にはこれはナップザック問題のように見えましたが、特定の長さの倍数がある可能性があるため、0/1ナップザック問題ではなく、有界ナップザック問題でした。(各アイテムの値をその重さとして扱います。)単純なアプローチ(および検索スペースの拡大を気にしない)を採用し、境界ナップザック問題を0/1ナップザック問題に変換するために使用した方法は、単に倍数を単数に分割し、よく知られている動的プログラミングアルゴリズムを適用します。残念ながら、これは次善の結果につながります。

たとえば、指定されたケーブル:
1 x 10ft、
1 x 7ft、
1 x 6ft、
5 x 3ft、
6 x 2ft、
7 x 1ft

ターゲットスパンが13フィートの場合、DPアルゴリズムは7 + 6を選択して距離をスパンします。貪欲なアルゴリズムは10 + 3を選択しますが、これはケーブルの最小数のネクタイです。15フィートをスパンしようとすると、問題が発生します。DPアルゴリズムは最終的に6 + 3 + 3 + 3を選択して4本のケーブルを取得しましたが、貪欲なアルゴリズムは3本のケーブルだけで10 + 3 + 2を正しく選択しました。

とにかく、境界を0/1に変換する軽いスキャンを行うと、複数のアイテムを{p、2p、4p ...}に変換するよく知られたアプローチのようです。私の質問は、p + 2p + 4pが複数のアイテムの数にならない場合、この変換がどのように機能するかです。たとえば、5本の3フィートケーブルがあります。3 + 2 x 3 + 4 x 3> 5 x 3であるため、{3、2x3、4x3}をあまりうまく追加できません。代わりに{3、4x3}を追加する必要がありますか?

[現在、「オレゴントレイルナップザックの問題」の論文を読み込もうとしていますが、現在使用されているアプローチは動的プログラミングではないようです。


1
私は、これは、よりに適していると思うだろうmath.stackexchange.comあるいはmathoverflow.net
オデッド

3
私は一般的なスタックオーバーフローとここの間で引き裂かれました。両方のサイトのFAQを読むと、このサイトにはデータ構造とアルゴリズムが最初にリストされています。数学サイトのFAQを読んで、代わりにcstheoryサイトに尋ねることを提案しているように見えました。
アリ

回答:


1

コードに何らかの間違いがある可能性があります。Naryshkinが述べたように、DPプログラムを書きました。ターゲットスパン13については6 + 7を報告し、15については2 + 6 + 7を報告します。

# weight: cable length
# total weight: target span
# value: 1 for each cable
# want minimum number of cables, i.e. minimum total value

def knapsack_01_exact_min(weights, values, W):
    # 0-1 knapsack, exact total weight W, minimizing total value
    n = len(weights)
    values = [0] + values
    weights = [0] + weights
    K = [[0 for i in range(W+1)] for j in range(n+1)]
    choice = [[0 for i in range(W+1)] for j in range(n+1)]
    for i in range(1, n+1):
        for w in range(1, W+1):
            K[i][w] = K[i-1][w]
            choice[i][w] = '|'
            if w >= weights[i]:
                t = K[i-1][w-weights[i]]
                if (w==weights[i] or t) and (K[i][w]==0 or t+values[i] < K[i][w]):
                    choice[i][w] = '\\'
                    K[i][w] = t+values[i]
    return K[n][W], choice

def print_choice(choice, weights):
    i = len(choice)-1
    j = len(choice[0])-1
    weights = [0] + weights
    while i > 0 and j > 0:
        if choice[i][j]=='\\':
            print weights[i],
            j -= weights[i]
        i -= 1
    print

lens = [10, 7, 6] + 5*[3] + 6*[2] + 7*[1]
values = (3+5+6+7)*[1]
span = 13
v, choice = knapsack_01_exact_min(lens, values, span)
print "need %d cables to span %d:" % (v,span),
print_choice(choice, lens)

span = 15
v, choice = knapsack_01_exact_min(lens, values, span)
print "need %d cables to span %d:" % (v,span),
print_choice(choice, lens)

入力長の順序を調整すると、他の最適なソリューションが得られます。たとえば、lens = 5*[3] + 6*[2] + 7*[1] + [10, 7, 6]15 = 10 + 2 + 3になります。


if文はどこで入手しましたか: 'if(w-weights [i] == 0 or t)and(K [i] [w] == 0 or t + values [i] <K [i] [w] ): '?今、私のDPアルゴリズムのソースを忘れて、私はまったくゼロのチェックがなかった、唯一の'(T +値[i]の<K [i]の[W])'をチェックした場合

1
正確な総重量を求めています。つまり、アイテムがピッキングされるたびに、(現在のステップの)正確な重量が満たされていることを確認する必要があります。そのため、アイテムを選択する場合、2番目の句「t + values [i] <K [i] [w]」により、合計値が小さくなります。ただし、その前に、必要な重量をフルフィルする必要があります。つまり、最初のi-1アイテムがウェイト(w-weights [i])をフルフィルできる必要があるため、最初の句「if K [i-1] [w -weights [i]] "(そのために一時変数tを使用しています)。
jsz

2つの追加チェック「w == weights [i]」および「K [i] [w] == 0」があります。それらは必要であり、テーブルの初期化方法が原因です。詳細は説明しないので、あなたはそれを作成できると思います。(w-weights [i] == 0をw == weights [i]に変更しました。より明確なはずです)。
jsz

1

私がバウンドナップザック問題を0/1に変換するのに使用したのを見た方法は、複数の同一のアイテムを持っていることです。次のアイテムがある場合は言います(重量、ユーティリティとして与えられます):

  • 2 x 1、2
  • 3 x 2、3

次のアイテムを使用して、0/1問題に変換します。

  • 1、2
  • 1、2
  • 2、3
  • 2、3
  • 2、3

そして、0/1アルゴリズムを使用して解決します。おそらく、正確性が等しい複数のソリューションがあるため、任意のソリューションを選択します。


あなたのワイヤーの問題について:ケーブルの長さはワイトで、各ケーブルの値はまったく同じです(1を呼び出しますが、正の値は機能します)。ここで、お気に入りのナップザック解法アルゴリズムを使用しますが、通常、値を最大化する(部分的な)ソリューションを選択する場合は、それを最小化するソリューションを選択します。また、容量に等しい総重量を持たないすべてのソリューションを無視します。誰かが望めば、おそらく実際のコードでより具体的なアルゴリズムを書くことができます。


うん、それはまさに私が重みと価値を埋めるためにやっていることです。私は最小値ではなく最大値を計算していました。あなたが提案したようにminを計算するコードを変更し、DPテーブルの行0をMAXINTに初期化しました。それでも同じ結果、ナップザック問題の動的プログラミングソリューションは、10 + 3 + 2または7 + 6 + 2の代わりに6 + 3 + 3 + 3を選択することになります。
アリ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.