Перетворення обмеженої проблеми з рюкзаком в задачу 0/1 для рубашки


12

Я зіткнувся з проблемою, де метою було використання динамічного програмування (замість інших підходів). Існує відстань, яку потрібно прокласти, і набір кабелів різної довжини. Яка мінімальна кількість кабелів, необхідних для точного проходження відстані?

Для мене це виглядало як проблема з рюкзаком , але, оскільки може бути множин певної довжини, це була проблема обмеженого рюкзака, а не проблема рюкзака 0/1. (Оцінюйте значення кожного предмета як його вагу.) Прийнявши наївний підхід (і не піклуючись про розширення пошукового простору), метод, який я використовував для перетворення обмеженої проблеми рюкзака в проблему рюкзака 0/1, був просто розбийте кратні на сингли та застосуйте відомий алгоритм динамічного програмування. На жаль, це призводить до неоптимальних результатів.

Наприклад, дані кабелі:
1 х 10
футів , 1 х 7 футів,
1 х 6 футів,
5 х 3 фути ,
6 х 2
фути , 7 х 1 фут

Якщо цільовий проміжок дорівнює 13 футів, алгоритм DP вибирає 7 + 6 для проходження відстані. Жадібний алгоритм вибрав би 10 + 3, але це прив'язка до мінімальної кількості кабелів. Проблема виникає при спробі перейти на 15 футів. Алгоритм DP підбирав 6 + 3 + 3 + 3 для отримання 4 кабелів, тоді як жадібний алгоритм правильно підбирає 10 + 3 + 2 лише для 3-х кабелів.

У будь-якому випадку, провівши легке сканування перетворень, обмежених 0/1, здається, добре відомий підхід перетворення декількох елементів у {p, 2p, 4p ...}. Моє запитання - як працює ця конверсія, якщо p + 2p + 4p не додає до кількості кількох елементів. Наприклад: у мене є 5 кабелів 3 фути. Я не можу дуже добре додати {3, 2x3, 4x3}, тому що 3 + 2x3 + 4x3> 5x3. Чи слід додати замість {3, 4x3}?

[На даний момент я намагаюся розглянути папір "Проблема штату Орегон Тракс", але зараз виглядає так, що підхід, який застосовується там, не є динамічним програмуванням.


1
Я думаю , що це більше підходить для math.stackexchange.com або навіть mathoverflow.net
Одед

3
Мене розірвало між загальним стаковерхом, і тут. Читаючи FAQ на обох сайтах, цей сайт спочатку перераховує структури даних та алгоритми. Читаючи поширені запитання щодо математичного сайту, здавалося, пропонується натомість запитати на сайті cstheory.
Мурахи

Відповіді:


1

Це може бути помилка у вашому коді. Я написав програму ДП, про яку згадував Наришкін. Для цільового проміжку 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-ваги [i] == 0 або t) і (K [i] [w] == 0 або t + значення [i] <K [i] [w] ): '? Якщо зараз забути джерело мого алгоритму DP, але я не мав нульових перевірок, перевіряйте лише на '(t + value [i] <K [i] [w])'
Мурахи

1
Ви вирішуєте точну загальну вагу, а це означає, що щоразу, коли вибираєте предмет, нам потрібно переконатися, що точна вага (поточного кроку) виконана. Отже, коли ми вирішимо вибрати предмет, другий пункт "t + значення [i] <K [i] [w]" гарантує, що ми матимемо менше загальне значення; але перед цим нам також потрібно заповнити необхідну вагу, тобто перші елементи i-1 повинні мати можливість заповнити вагу (w-ваги [i]), отже, і перше застереження "якщо K [i-1] [w -weights [i]] "(для цього я використовую тимчасову змінну t).
jsz

Є дві додаткові позначки "w == ваги [i]" та "K [i] [w] == 0"; вони необхідні і завдяки тому, як ініціалізуються таблиці; Я думаю, ви зможете розібратися, тому я не буду вникати в деталі. (Я змінив w-ваги [i] == 0 на w == ваги [i]; це повинно бути чіткіше).
jsz

1

Спосіб, який я бачив, для перетворення обмеженої проблеми з рюкзаком у 0/1 - це просто мати кілька однакових елементів. Скажіть, якщо у вас є такі елементи (вказані як вага, корисність):

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

Ви б перетворили його на проблему 0/1, використовуючи елементи з

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

І використовуйте алгоритм 0/1 для його вирішення. Ви, ймовірно, матиме кілька рішень однакової коректності, тому ви виберете довільне.


Тепер про вашу проблему з дротом: я б вважав, що довжина кабелю повинна бути вагою, а значення кожного кабелю точно однаковим (називайте його 1, хоча будь-яке позитивне значення буде працювати). Тепер використовуйте улюблений алгоритм вирішення Knapsack, але там, де зазвичай вибираєте (часткове) рішення, яке максимально збільшує значення, вибирайте таке, яке мінімізує його. Крім того, ігноруйте всі рішення, які не мають загальної ваги, що дорівнює ємності. Я, мабуть, можу (спробувати) написати більш конкретний алгоритм з фактичним кодом, якщо хтось цього хоче.


Так, саме це я роблю, щоб заповнити вагу та цінність. Я обчислював максимальне значення, а не хв. Я тільки що змінив код для обчислення за хв, як ви запропонували, і ініціалізував рядок 0 таблиці DP, щоб він був МАКСИНТ. Незважаючи на той самий результат, динамічне рішення програмування для проблем із рюкзаком все ще закінчується вибором 6 + 3 + 3 + 3 замість 10 + 3 + 2 або 7 + 6 + 2.
Мурахи
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.