Analysis of five major algorithms

greedy algorithm

The greedy algorithm can obtain the local optimal solution of the problem, but it may not be able to obtain the global optimal solution. At the same time, the quality of the optimal solution depends on the choice of the greedy strategy. The characteristic is that it is simple and can obtain a local optimal solution. Just like the dog-beating stick method, with the same set of stick methods, Hong Qigong and Lu Youjiao's level is much different, so it is also a greedy algorithm, and different greedy strategies will lead to very different results

def buildItem():
    names=['A','B','C','D','E','F','G']
    vals = [35,30,6,50,40,10,25]
    weights=[10,40,30,50,35,40,30]
    Items=[]
    for i in range(len(names)):
        Items.append(Item(names[i],vals[i],weights[i]))
    return Items

def testGreedy(items,constraint,keyFunction):
    taken,val=greedy(items,constraint,keyFunction)
    print 'Total value of items taken = ', val
    for item in taken:
        print ' ', item


def testGreedys(maxWeight = 150):
    items = buildItem()

    print 'Use greedy by value to fill knapsack of size', maxWeight 
    testGreedy(items, maxWeight, value)

    print '\n Use greedy by weight to fill knapsack of size', maxWeight
    testGreedy(items, maxWeight, weightInverse)

    print '\n Use greedy by density to fill knapsack of size', maxWeight
    testGreedy(items, maxWeight, density)

Exhaustive method

Exhaustive method, also known as classification proof, classification analysis proof, complete induction or violence method, is a mathematical proof method, which divides the propositions to be proved into a limited number of situations or a set of equivalent situations, and then according to each It is a direct method of proof to test whether the proposition is true or not . The proof of the exhaustive method includes two stages: Prove that the classification is complete, that is to say, each case to be proved meets the conditions of (at least) one class of cases; Prove each class of cases separately.

def exhaustive_search(target, candidates):
    results = []
    for candidate in candidates:
        if candidate == target:
            results.append(candidate)
    return results

# 示例调用
target = 5
candidates = [1, 2, 3, 4, 5, 6, 7]
results = exhaustive_search(target, candidates)
print(results)

Dynamic programming algorithm

The dynamic programming algorithm is to split a problem into sub-problems until the sub-problems can be solved directly.

(often splitting subproblems by obtaining a recursive functional relation)

Then save the sub- question answers to reduce double counting.

Finally, according to the answer of the sub-question , it is a method to deduce the solution of the original problem from the bottom up .

The common ones are the Fibonacci sequence and frogs jumping steps .

def knapsack(weights, values, capacity):
    n = len(weights)
    dp = [[0] * (capacity + 1) for _ in range(n+1)]
    
    for i in range(1, n+1):
        for j in range(1, capacity+1):
            if weights[i-1] <= j:
                dp[i][j] = max(dp[i-1][j], values[i-1] + dp[i-1][j-weights[i-1]])
            else:
                dp[i][j] = dp[i-1][j]

    chosen_items = []
    w = capacity
    for i in range(n, 0, -1):
        if dp[i][w] != dp[i-1][w]:
            chosen_items.append(i-1)
            w -= weights[i-1]

    return dp[n][capacity], chosen_items

# 示例调用
weights = [2, 3, 4, 5]
values = [3, 4, 5, 6]
capacity = 5
max_value, chosen_items = knapsack(weights, values, capacity)
print("Max Value:", max_value)
print("Chosen Items:", chosen_items)

Greedy Algorithm

Greedy algorithm (greedy algorithm, also known as greedy algorithm) means that when solving a problem, always make the best choice at present . That is to say, without considering the overall optimality, the algorithm obtains a local optimal solution in a certain sense. The greedy algorithm cannot obtain the overall optimal solution for all problems, the key is the choice of greedy strategy.

def make_change(coins, amount):
    coins.sort(reverse=True)  # 将硬币面额按降序排列
    change = []
    
    for coin in coins:
        while amount >= coin:
            change.append(coin)
            amount -= coin
    
    if amount != 0:
        return "无法找零"
    
    return change

# 示例调用
coins = [1, 5, 10, 25]
amount = 36
change = make_change(coins, amount)
print("找零方案:", change)

Backtracking

The backtracking method is a selective search method, also known as the heuristic method. This method finds all solutions that satisfy the condition .

First, search forward according to the optimal conditions, and try to achieve the goal.

When a certain step is explored, it is found that the original choice is not optimal or the goal cannot be achieved , so take a step back and choose again.

This technique of going back and changing the road if it doesn't work is called the backtracking method, and the point of a certain state that satisfies the backtracking condition is called the "backtracking point".

The backtracking method usually searches the solution space in a depth-first (DFS) manner , and uses pruning functions to avoid invalid searches during the search process .

It 's a bit exhaustive , and exhaustion can also be regarded as a temptation, but the backtracking method is a smarter exhaustion.

Common eight queens problem , split palindrome string

def backtrack(nums, path, result):
    if len(path) == len(nums):
        result.append(path[:])
        return
    
    for num in nums:
        if num not in path:
            path.append(num)
            backtrack(nums, path, result)
            path.pop()

# 示例调用
nums = [1, 2, 3]
result = []
backtrack(nums, [], result)
print("全排列结果:", result)

branch and bound

The so-called branch is to use the breadth-first (BFS) method to sequentially search all branches of the current node, that is, all adjacent nodes.

The nodes that do not meet the conditions are discarded, and the remaining nodes are added to the active node list.

Then choose a node from the table (strategic choice) as the next node,

The search continues until the desired solution is found or the list of slipnodes is empty.

The solution goal of the branch and bound method is to find a solution that satisfies the conditions as soon as possible, or to find the optimal solution among the solutions that satisfy the conditions .

The common ones are 01 knapsack problem , traveling salesman problem

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

def knapsack(items, capacity):
    items.sort(key=lambda x: x.value / x.weight, reverse=True)
    
    n = len(items)
    max_value = 0
    curr_weight = 0
    curr_value = 0
    best_solution = []
    stack = [(0, curr_weight, curr_value, [])]
    
    while stack:
        i, curr_weight, curr_value, chosen_items = stack.pop()
        
        if i >= n or curr_weight == capacity:
            if curr_value > max_value:
                max_value = curr_value
                best_solution = chosen_items
            continue
        
        item = items[i]
        
        if curr_weight + item.weight <= capacity:
            stack.append((i+1, curr_weight+item.weight, curr_value+item.value, chosen_items+[item]))
        
        upper_bound = curr_value + (capacity - curr_weight) * (item.value / item.weight)
        if upper_bound > max_value:
            stack.append((i+1, curr_weight, curr_value, chosen_items))
    
    return max_value, best_solution

# 示例调用
items = [Item(2, 3), Item(3, 4), Item(4, 5), Item(5, 6)]
capacity = 5
max_value, best_solution = knapsack(items, capacity)
print("最大价值:", max_value)
print("最佳解决方案:", [(item.weight, item.value) for item in best_solution])

Guess you like

Origin blog.csdn.net/NOguang/article/details/131905234