Algorithm -- dynamic programming

Posted by jbruns on Wed, 05 Jan 2022 01:45:34 +0100

dynamic programming

  • definition
    dynamic programming (DP): finding the optimal solution under multiple branches

  • working principle
    To solve a complex problem, first solve its sub problems (first solve the sub problems, and then gradually solve the big problems)
    This is a typical recursive idea, eg: fiborache sequence

  • Application scenario

The definition of fiborache sequence is as follows: F (0) = 1, f (1) = 1, f (n) = f (n-1) + F (n-2) (n > = 2, n belongs to any positive integer)

Code implementation:

def fib(i: int):
    if i <= 1:
        return 1
    return fib(i-1) + fib(i-2)

[disadvantages]
When n is large enough, the program runs time-consuming, and the number of iterations is too many, and the function stack overflows.
Optimization scheme:
Use a number to save the calculated data to avoid repeated calculation of dynamic programming

  • Classical problem
    1. Knapsack problem
    0-1 Backpack
    [question] a backpack with a capacity of V and some items. An item has two attributes, volume w and value v,
    There is only one item of each kind. Requirements: pack as many items as possible under the back, and seek the maximum value, backpack
    Can not be filled.
    0-1 knapsack problem: in the optimal solution, there are only two possibilities in each item, in the knapsack and not in the knapsack.
    Step 1 [find sub problem]:
    Subproblems are related to items. Each item has two results: can be loaded and can't be loaded.
    >A. the reported capacity is smaller than the volume of the article and cannot be loaded. At this time, the maximum value is the same as that of the first i-1 article
    The maximum value is the same.
    >B. the capacity is enough to hold the article, but it is not necessarily greater than the current optimal value of the same volume, so it is necessary to
    Compare. Therefore, the number of items and Backpack Capacity in the subproblem should be regarded as variables. Subproblem
    When determining the backpack capacity, find the maximum value that the first i items can achieve.
    Step 2 [determine status]: when the "value" corresponding to the "status" is the backpack capacity, find the maximum that the first i items can reach
    Value set to dp[i][j]. Initial, dp[0] j 0, no item and no value.
    Step 3 [determine state transition equation]: if the volume of the ith article is w[i] and the value is v[i], the state transition equation is:
    *J < W, DP [i] [J] = DP [I-1] [J] / / the item cannot be packed on the back, j: current Backpack Capacity
    * j>=w, dp[i][j] = max{dp[i-1][j-w[i]]+v[i], dp[i-1][j]}
from typing import List


def dynamic_p()->List:
    items = [                               # Item
        {"name": "water", "weight": 3, "value": 10},
        {"name": "book", "weight": 1, "value": 3},
        {"name": "food", "weight": 2, "value": 9},
        {"name": "pocket knife", "weight": 3, "value": 4},
        {"name": "Clothing", "weight": 2, "value": 5},
        {"name": "mobile phone", "weight": 1, "value": 10}
    ]
    max_capacity = 6                             # The constraint condition is that the maximum load of the backpack is 6
    dp = [[0] * (max_capacity + 1) for _ in range(len(items) + 1)]

    for row in range(1, len(items) + 1):  # Row stands for row
        for col in range(1, max_capacity + 1):  # col stands for column
            weight = items[row - 1]["weight"]  # Get current item weight
            value = items[row - 1]["value"]  # Get current item value
            if weight > col:  # Judge whether the item weight is greater than the current backpack capacity
                dp[row][col] = dp[row - 1][col]  # If it is greater than the previous optimal result, row-1 represents the previous row
            else:
                # Use the built-in function max() to compare the last optimal result with the current item value + available value of remaining space to obtain the maximum value
                dp[row][col] = max(value + dp[row - 1][col - weight], dp[row - 1][col])
    return dp
  • Complete knapsack problem
    There are N items and a backpack with a capacity of V. there are unlimited items available for each item.

The volume of article I is v[i], and the value is w[i]. Find out which items are loaded into the backpack so that the total cost of these items does not exceed the backpack capacity,

And the total value is the largest.

from typing import List


class Thing(object):
    """
    Items, Used to define data structures,
    When the data size is large, classes are usually used to define the data structure
    """

    def __init__(self, weight, value):
        self.weight = weight
        self.value = value


def dynamic01(things: List[Thing], capacity: int):
    """
    01 knapsack problem 
    :param weight:
    :param value:
    :return:
    """

    n = len(things)  # Number of items
    v = capacity # Backpack Capacity
    f = [0] * v # Total value
    # The time and space responsibility before optimization is: v*n
    # for i in range(n):
    #     for j in range(v, -1, -1):
    #         f[j] = max(f[j], f[j - things[i].weight] + things[i].value)
    # There is no optimization space in time, and the optimized space is n
    for i in range(n):
        for j in range(v, things[i].weight, -1):
            f[j-1] = max(f[j-1], f[j - things[i].weight - 1] + things[i].value)

    return max(f)


def dynamic02(N: int, V: int, things:List[Thing]):
    """
    Complete knapsack problem
    :param N: Item type
    :param V: Backpack Capacity
    :param things: Item details
    :return:
    """
    if N == 0 or V == 0:
        return 0
    dp = [0] * (V + 1)
    for i in range(N):
        for j in range(things[i].weight, V, 1):
            dp[j] = max(dp[j], dp[j-things[i].weight] + things[i].value)

    return dp[V]


def to_int(num_list: List):
    """
    Convert input characters to numbers
    :param num_list:
    :return:
    """
    if not num_list:
        return []
    if isinstance(num_list[0], list):
        res = []
        for l in num_list:
            res.append(to_int(l))
        return res

    else:
        return [int(num) for num in num_list]

def main():
    print(f"01 Backpack:\n")
    n = input("Please enter the total number of items N:")
    v = input("Backpack volume V:")
    n = int(n)
    v = int(v)
    array = list()
    print("Please enter the volume and value of the item (separated by spaces)\n")
    while n > 0:
        arr = input()
        if arr is None:
            continue
        array.append(arr.strip().split(' '))
        n -= 1

    array = to_int(array)
    things = []
    for arr in array:
        thing = Thing(arr[0], arr[1])
        things.append(thing)

    max_value = dynamic01(things, v)

    print(max_value)

Topics: Python data structure Dynamic Programming