Рекурсивный алгоритм с использованием мемоизации

Моя проблема заключается в следующем: у меня есть список миссий, каждая из которых занимает определенное количество времени и дает определенное количество очков, и время k, отводимое на их выполнение:

например: missions = [(14,3),(54,5),(5,4)] и time = 15

в этом примере у меня есть 3 миссии, и первая дает мне 14 очков и занимает 3 минуты. Всего у меня 15 минут. Каждая миссия представляет собой кортеж, первое значение которого представляет собой количество очков за эту миссию, а второе значение - количество минут, необходимых для выполнения этой миссии.

Я должен рекурсивно с помощью мемоизации найти максимальное количество очков, которое я могу получить за данный список миссий и за заданное время.

Я пытаюсь реализовать функцию под названием select (mission, time), которая будет работать рекурсивно и использовать функцию choose_mem (mission, time, mem, k) для достижения моей цели. функция select_mem должна получить «k» - количество миссий на выбор, а mem - пустой словарь mem, который будет содержать все проблемы, которые уже были решены ранее.

Это то, что я получил до сих пор, мне нужна помощь в реализации того, что требуется выше, я имею в виду использование словаря (который в настоящее время просто существует и все время пуст), а также тот факт, что мой ввод функции select_mem равен i,j,missions,d, и он должен быть choose_mem(missions, time, mem, k) где mem = d и k - количество миссий на выбор.

Если кто-нибудь может помочь мне настроить мой код, я был бы очень признателен.

mem = {}

def choose(missions, time):
    j = time
    result = []
    for i in range(len(missions), 0, -1):
        if choose_mem(missions, j, mem, i) != choose_mem(missions, j, mem, i-1):
            j -= missions[i - 1][1]
    return choose_mem(missions, time, mem, len(missions)) 

def choose_mem(missions, time, mem, k): 
    if k == 0: return 0
    points, a = missions[k - 1]
    if a > time:
        return choose_mem(missions, time, mem, k-1) 
    else:
        return max(choose_mem(missions, time, mem, k-1),
                   choose_mem(missions, time-a, mem, k-1) + points)

person Matthew D    schedule 10.05.2013    source источник
comment
Это только у меня, или ты никогда не обновляешь свой словарь?   -  person pcalcao    schedule 10.05.2013
comment
Вы правы, и я написал это над кодом, если вы заметили. Это одна из тех вещей, с которыми мне нужно познакомиться с моим кодом.   -  person Matthew D    schedule 10.05.2013
comment
Отредактировал мой ответ, надеюсь, это поможет.   -  person pcalcao    schedule 10.05.2013
comment
Это помогло. Я немного изменил свой код, поэтому сейчас думаю, что это более понятно. У меня все на месте. Единственное, что мне нужно сделать сейчас, это проверить, содержит ли «mem» = мой словарь ответ, который я ищу. Я действительно боролся с этим, и я не мог найти способ добавить словарь в свой код, который имел бы смысл. Не могли бы вы протянуть мне последнюю руку помощи, чтобы я смог закончить эту программу?   -  person Matthew D    schedule 10.05.2013
comment
Обновите мой ответ ссылкой, которая может вам пригодиться.   -  person pcalcao    schedule 10.05.2013


Ответы (1)


Это немного расплывчато, но ваша проблема грубо переведена на очень известную NP-полную задачу - задачу о ранце.

Вы можете прочитать об этом немного больше в Википедии, если вы замените вес временем, у вас возникнут проблемы.

Динамическое программирование - распространенный способ решения этой проблемы, как вы можете видеть здесь: http://en.wikipedia.org/wiki/Knapsack_problem#Dynamic_programming

С практической точки зрения мемоизация более или менее эквивалентна динамическому программированию, так что не позволяйте причудливому названию вводить вас в заблуждение.

Основная концепция заключается в том, что вы используете дополнительную структуру данных для хранения частей вашей проблемы, которую вы уже решили. Поскольку решение, которое вы реализуете, является рекурсивным, многие подзадачи будут перекрываться, а мемоизация позволяет вам вычислить каждую из них только один раз.

Итак, самая сложная часть для вас - подумать о своей проблеме, о том, что вам нужно сохранить в словаре, чтобы, когда вы вызываете choose_mem со значениями, которые вы уже вычислили, вы просто извлекаете их из словаря, вместо того, чтобы выполнять еще один рекурсивный вызов.

Если вы хотите проверить реализацию общей задачи о рюкзаке 0-1 (ваш случай, поскольку вы не можете добавлять элементы частично), то это показалось мне хорошим ресурсом:

https://sites.google.com/site/mikescoderama/Home/0-1-knapsack-problem-in-p

Это хорошо объяснено, и код достаточно читабелен. Если вы понимаете, как используется матрица для хранения затрат, тогда ваша проблема будет решена за вас.

person pcalcao    schedule 10.05.2013
comment
Вау, да, я только что проверил задачу о рюкзаке в википедии, и она кажется почти такой же, как у меня (за исключением того, что это вес, а не время, как вы указали). Спасибо за помощь. Я обязательно постараюсь использовать там информацию для решения своей проблемы. - person Matthew D; 10.05.2013
comment
Если вы можете взглянуть на новый код, который я только что отредактировал, мы будем очень признательны. Код действительно работает сейчас, но меня спросили о конкретном типе функции, то есть select_mem должен выглядеть так: choose_mem (mission, time, mem, k), где mem - это словарь 'd', а k - количество миссий левый. - person Matthew D; 10.05.2013