五大算法解析

贪婪算法

贪婪算法可以获取到问题的局部最优解,不一定能获取到全局最优解,同时获取最优解的好坏要看贪婪策略的选择。特点就是简单,能获取到局部最优解。就像打狗棍法,同一套棍法,洪七公和鲁有脚的水平就差太多了,因此同样是贪婪算法,不同的贪婪策略会导致得到差异非常大的结果

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)

穷举法

穷举法,亦称作分类证明、分类分析证明、完全归纳法或暴力法,是一种数学证明方法, 它将所求证的命题分为有限种情形或是等价情形的集合,接着依每种类型分别检验该命题是否成立,此乃一种直接证明法。 穷举法证明包括两阶段: 证明分类是完全的, 也就是说每一个待证的个例皆符合(至少)一类情形的条件; 分别对每一类情形给出证明。

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)

动态规划算法

动态规划算法是把一个问题,拆成一个个子问题,直到子问题可以直接解决。

(常常是通过得到一个递推的函数关系式来拆分子问题)

然后把子问题答案保存,以减少重复计算。

最后根据子问题答案反推(自底向上推),得出原问题解的一种方法。

常见的有斐波那契数列青蛙跳台阶

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,又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。 也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择。

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)

回溯法

回溯法是一种选优搜索法,又称为试探法。该方法可以找到所有满足条件的解

首先按选优条件向前搜索,尝试能否达到目标。

当探索到某一步时,发现原先选择不是最优达不到目标,就退回一步重新选择。

这种走不通就退回换条路再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

回溯法常常以深度优先(DFS)方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

有点穷举的意思,穷举也可以看做一种试探,但回溯法是一种更聪明的穷举。

常见的有八皇后问题分割回文串

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)

分支限界法

所谓分支就是采用广度优先(BFS)方式依次搜索当前结点的所有分支,也就是所有相邻的结点。

抛弃不满足条件的结点,其余节点加入活结点表。

然后从表中选择一个结点(有策略的选择)作为下一个结点,

继续搜索直至到找到所需的解或活结点表为空时为止。

分支限界法的求解目标则是尽快找出满足条件的一个解,或是在满足条件的解中找出最优解

常见的有01背包问题旅行商问题

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])

猜你喜欢

转载自blog.csdn.net/NOguang/article/details/131905234