Member 13615317 Ответов: 0

Я не понимаю рекурсии в этом фрагменте кода


У меня есть этот алгоритм с этим фрагментом рекурсивного кода, который в основном является решением проблемы рюкзака с помощью грубой силы.

Где у меня есть лимит калорий 750, и поэтому я хочу найти коллекцию продуктов, которые имеют самую высокую общую ценность, оставаясь ниже или равными 750 калориям.

Однако я не понимаю этого алгоритма.

class Food(object):
    def __init__(self, n, v, w):
        self.name = n
        self.value = v
        self.calories = w

    def getValue(self):
        return self.value

    def getCost(self):
        return self.calories

    def density(self):
        return self.getValue() / self.getCost()

    def __str__(self):
        return self.name + ': <' + str(self.value) \
               + ', ' + str(self.calories) + '>'


def buildMenu(names, values, calories):
    menu = []
    for i in range(len(values)):
        menu.append(Food(names[i], values[i],
                         calories[i]))
    return menu

#This is where I'm getting confused
def maxVal(toConsider, avail):
    if toConsider == [] or avail == 0:
        result = (0, ())

    elif toConsider[0].getCost() > avail:
        result = maxVal(toConsider[1:], avail)

    else:
        nextItem = toConsider[0]
        withVal, withToTake = maxVal(toConsider[1:],
                                     avail - nextItem.getCost())
        withVal += nextItem.getValue()
        withoutVal, withoutToTake = maxVal(toConsider[1:], avail)

        if withVal > withoutVal:
            result = (withVal, withToTake + (nextItem,))

        else:
            result = (withoutVal, withoutToTake)

    return result


def testMaxVal(foods, maxUnits, printItems=True):
    print('Use search tree to allocate', maxUnits,
          'calories')
    val, taken = maxVal(foods, maxUnits)
    print('Total value of items taken =', val)
    if printItems:
        for item in taken:
            print('   ', item)


names = ['wine', 'beer', 'pizza', 'burger', 'fries',
         'cola', 'apple', 'donut', 'cake']
values = [89, 90, 95, 100, 90, 79, 50, 10]
calories = [123, 154, 258, 354, 365, 150, 95, 195]
foods = buildMenu(names, values, calories)

print('')
testMaxVal(foods, 750)


Когда я положил
print(toConsider)
под первой строкой кода здесь, чтобы я мог видеть размер списка, я замечаю, что он колеблется.

Но то, что я вижу, если вы представляете себе "toConsider" как список, это то, что сразу же попадает в него

withVal, withToTake = maxVal(toConsider[1:],
                                 avail - nextItem.getCost())

или если это удовлетворяет

elif toConsider[0].getCost() > avail:


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

В каком это случае

if toConsider == [] or avail == 0:
    result = (0, ())


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

Моя путаница заключается в том, что даже если return равен (0, ()) в одной точке, а toConsider-это []

а. как программа все еще продолжает работать после "возврата" в коде, который также вызывает...(заявление ниже)

b. как toConsider может каким-то образом "регенерировать" некоторые элементы обратно.

потому что выход есть

Используйте дерево поиска, чтобы выделить 750 калорий
Общая стоимость взятых предметов = 353
Кола: <79, 150>
пицца: <95, 258>
пиво: <90, 154>
вино: <89, 123>

в то время как если я посмотрю на код и визуализирую его на python tutor, я ожидаю, что

(0,())

Что я уже пробовал:

Я попытался использовать programming tutor для решения своей проблемы, однако, как только она доходит до шага 199, toConsider внезапно имеет в себе пончик! то есть элемент. Когда у него ничего не должно быть. Вот ссылка


Member 13615317

Я прикрепил ссылку, но она не появилась.

Он так и есть но это довольно долго извините

http://www.pythontutor.com/live.html#code=class%20Food%28object%29%3A%0A%20%20%20%20def%20__init__%28self,%20n,%20v,%20w%29%3A%0A%20%20%20%20%20%20%20%20self.name%20%3D%20n%0A%20%20%20%20%20%20%20%20self.value%20%3D%20v%0A%20%20%20%20%20%20%20%20self.calories%20%3D%20w%0A%0A%20%20%20%20def%20getValue%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20self.value%0A%0A%20%20%20%20def%20getCost%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20self.calories%0A%0A%20%20%20%20def%20density%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20self.getValue%28%29%20/%20self.getCost%28%29%0A%0A%20%20%20%20def%20__str__%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20self.name%20%2B%20'%3A%20%3C'%20%2B%20str%28self.value%29%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20',%20'%20%2B%20str%28self.calories%29%20%2B%20'%3E'%0A%0A%0Adef%20buildMenu%28names,%20values,%20calories%29%3A%0A%20%20%20%20menu%20%3D%20%5B%5D%0A%20%20%20%20for%20i%20in%20range%28len%28values%29%29%3A%0A%20%20%20%20%20%20%20%20menu.append%28Food%28names%5Bi%5D,%20values%5Bi%5D,%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20calories%5Bi%5D%29%29%0A%20%20%20%20return%20menu%0A%0A%0Adef%20maxVal%28toConsider,%20avail%29%3A%0A%20%20%20%20if%20toConsider%20%3D%3D%20%5B%5D%20or%20avail%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20result%20%3D%20%280,%20%28%29%29%0A%0A%20%20%20%20elif%20toConsider%5B0%5D.getCost%28%29%20%3E%20avail%3A%0A%0A%20%20%20%20%20%20%20%20result%20%3D%20maxVal%28toConsider%5B1%3A%5D,%20avail%29%0A%20%20%20%20else%3A%0A%0A%20%20%20%20%20%20%20%20nextItem%20%3D%20toConsider%5B0%5D%0A%0A%20%20%20%20%20%20%20%20withVal,%20withToTake%20%3D%20maxVal%28toConsider%5B1%3A%5D,%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20avail%20-%20nextItem.getCost%28%29%29%0A%0A%20%20%20%20%20%20%20%20withVal%20%2B%3D%20nextItem.getValue%28%29%0A%0A%20%20%20%20%20%20%20%20withoutVal,%20withoutToTake%20%3D%20maxVal%28toConsider%5B1%3A%5D,%20avail%29%0A%0A%20%20%20%20%20%20%20%20if%20withVal%20%3E%20withoutVal%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20%28withVal,%20withToTake%20%2B%20%28nextItem,%29%29%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20%28withoutVal,%20withoutToTake%29%0A%20%20%20%20return%20result%0A%0A%0Adef%20testMaxVal%28foods,%20maxUnits,%20printItems%3DTrue%29%3A%0A%20%20%20%20print%28'Use%20search%20tree%20to%20allocate',%20maxUnits,%0A%20%20%20%20%20%20%20%20%20%20'calories'%29%0A%20%20%20%20val,%20taken%20%3D%20maxVal%28foods,%20maxUnits%29%0A%20%20%20%20print%28'Total%20value%20of%20items%20taken%20%3D',%20val%29%0A%20%20%20%20if%20printItems%3A%0A%20%20%20%20%20%20%20%20for%20item%20in%20taken%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print%28'%20%20%20',%20item%29%0A%0A%0Anames%20%3D%20%5B'wine',%20'beer',%20'pizza',%20'burger',%20'fries',%0A%20%20%20%20%20%20%20%20%20'cola',%20'apple',%20'donut',%20'cake'%5D%0Avalues%20%3D%20%5B89,%2090,%2095,%20100,%2090,%2079,%2050,%2010%5D%0Acalories%20%3D%20%5B123,%20154,%20258,%20354,%20365,%20150,%2095,%20195%5D%0Afoods%20%3D%20buildMenu%28names,%20values,%20calories%29%0A%0Aprint%28''%29%0AtestMaxVal%28foods,%20750%29&cumulative=false&curInstr=999&heapPrimitives=false&mode=display&origin=opt-live.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false

0 Ответов