Sınırlı bir sırt çantası sorununu 0/1 sırt çantası sorununa dönüştürme


12

Hedefin dinamik programlama kullanmak olduğu bir problemle karşılaştım (diğer yaklaşımlar yerine). Uzatılacak bir mesafe ve farklı uzunluklarda bir kablo seti vardır. Mesafeyi tam olarak katlamak için gereken minimum kablo sayısı nedir?

Bana göre bu bir sırt çantası sorununa benziyordu , ancak belirli bir uzunluğun katları olabileceğinden, 0/1 sırt çantası probleminden ziyade sınırlı bir sırt çantası problemiydi. (Her öğenin değerini ağırlık olarak değerlendirin.) Saf yaklaşımı (ve arama alanının genişlemesini umursamadan), sınırlı sırt çantası problemini 0/1 sırt çantası problemine dönüştürmek için kullandığım yöntem, katları tekli parçalara ayırın ve iyi bilinen dinamik programlama algoritmasını uygulayın. Ne yazık ki, bu optimal olmayan sonuçlara yol açar.

Örneğin, verilen kablolar:
1 x 10ft,
1 x 7ft,
1 x 6ft,
5 x 3ft,
6 x 2ft,
7 x 1ft

Hedef açıklık 13ft ise, DP algoritması mesafeyi yaymak için 7 + 6'yı seçer. Açgözlü bir algoritma 10 + 3 seçebilirdi, ancak minimum sayıda kablo için bir bağ. Sorun 15ft yayılmaya çalışırken ortaya çıkar. DP algoritması 4 kablo almak için 6 + 3 + 3 + 3'ü seçerken, açgözlü algoritma sadece 3 kablo için 10 + 3 + 2'yi doğru seçiyor.

Her neyse, 0/1 ile sınırlı dönüşüm yapmak için hafif bir tarama yapmak, birden fazla öğeyi {p, 2p, 4p ...} 'ye dönüştürmek için iyi bilinen bir yaklaşım gibi görünüyor. Benim sorum, p + 2p + 4p birden fazla öğe sayısına eklenmezse bu dönüşümün nasıl çalıştığıdır. Örneğin: 5 adet 3ft kablom var. {3, 2x3, 4x3} 'i çok iyi ekleyemiyorum çünkü 3 + 2x3 + 4x3> 5x3. Bunun yerine {3, 4x3} eklemeli miyim?

[Şu anda "Oregon Trail Sırt Çantası Sorunu" belgesini bulmaya çalışıyorum, ancak şu anda kullanılan yaklaşım dinamik programlama yok gibi görünüyor.]



3
Genel yığın akışı arasında ve burada kaldım. Her iki sitedeki SSS'leri okuyarak, bu site önce veri yapılarını ve algoritmaları listeler. Matematik sitesi için SSS okumak, bunun yerine cstheory sitesinde sormak gibi görünüyordu.
Karıncalar

Yanıtlar:


1

Kodunuzda bir hata olabilir. DP programını Naryshkin'in belirttiği gibi yazdım. Hedef açıklık 13 için 6 + 7 bildirir ve 15 için 2 + 6 + 7 bildirir.

# 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)

Giriş uzunluklarının sırasını ayarlarsanız, diğer en uygun çözümleri verebilir. Örneğin, lens = 5*[3] + 6*[2] + 7*[1] + [10, 7, 6]15 = 10 + 2 + 3 verecektir.


İf ifadesini nereden aldınız: 'if (w-ağırlıkları [i] == 0 veya t) ve (K [i] [w] == 0 veya t + değerleri [i] <K [i] [w] ): '? Şimdi DP algoritmamın kaynağını unutursam, ancak sıfır kontrolüm yoktu, sadece '(t + değeri [i] <K [i] [w])' için kontrol edin
Karıncalar

1
Sen için çözme kesin bir öğe aldı her nekadar biz karşılanmaktadır (cari adımın) emin kesin ağırlık yapmak gerektiğini hangi araçlar, toplam ağırlığı. Dolayısıyla, bir öğe seçmeye karar verdiğimizde, ikinci "t + değerleri [i] <K [i] [w]" yan tümcesi daha küçük bir toplam değere sahip olmamızı sağlar; ancak ondan önce, gerekli ağırlığı da doldurmamız gerekiyor, yani ilk i-1 öğelerinin ağırlığı (w-ağırlıklar [i]), yani ilk olarak "eğer K [i-1] [w -weights [i]] "(Bunun için geçici bir değişken t kullanıyorum).
jsz

"W == ağırlıklar [i]" ve "K [i] [w] == 0" olmak üzere iki ek kontrol daha vardır; gerekli ve tabloların nasıl başlatıldığı nedeniyle; Bence bunu başarabileceksiniz, böylece ayrıntılara girmeyeceğim. (W-ağırlıkları [i] == 0 değerini w == ağırlıkları [i] olarak değiştirdim; daha açık olmalı).
jsz

1

Sınırlı bir sırt çantası problemini 0 / 1'e dönüştürmek için kullandığım yol, sadece birden fazla özdeş öğeye sahip olmaktır. Aşağıdaki öğeleriniz varsa (ağırlık, yardımcı program olarak verilir) söyleyin:

  • 2 x 1, 2
  • 3 x 2, 3

Aşağıdaki öğeleri kullanarak 0/1 sorununa dönüştürürsünüz

  • 1, 2
  • 1, 2
  • 2, 3
  • 2, 3
  • 2, 3

Ve çözmek için 0/1 algoritması kullanın. Muhtemelen eşit doğrulukta birden fazla çözümünüz olacaktır, böylece keyfi bir çözüm seçersiniz.


Şimdi tel probleminiz hakkında: Kablo uzunluğunun wight olması ve her kablonun değerinin tamamen aynı olması gerekir (herhangi bir pozitif değer çalışmasına rağmen 1'i çağırın). Şimdi, en sevdiğiniz Knapsack çözme algoritmasını kullanın, ancak normalde değeri en üst düzeye çıkaran (kısmi) bir çözüm seçeceğiniz yerde, en aza indiren bir çözüm seçin. Ayrıca, kapasiteye eşit toplam ağırlığı olmayan tüm çözümleri göz ardı edin. Muhtemelen (isterse) gerçek kod ile daha somut bir algoritma yazmayı deneyebilirsiniz.


Evet, ağırlık ve değeri doldurmak için yaptığım şey tam olarak bu. Min yerine maksimum değer hesaplıyordum. Ben sadece şimdi önerdiğin gibi min için hesaplamak için kod değiştirdi ve DP tablosunun 0 satır MAXINT olarak başlattı. Yine aynı sonuç, sırt çantası problemleri için dinamik programlama çözümü, 10 + 3 + 2 veya 7 + 6 + 2 yerine 6 + 3 + 3 + 3 almaya devam ediyor.
Karıncalar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.