五大算法及示例

1、分治法

把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题,直到最后子问题可以简单的直接求解,子问题的解的合并即是原问题的解。

二分查找算法:

# 查找的数字
array = [i for i in range(100)]
# 首位值
low = 0
# 末位值
height = len(array)-1
# 设定需要找到的数字
num = 3

# 循环查找
while True:
    # 获取中位数
    mid = int((low+height)/2)
    print(array[mid])
    # 如果中位数小于查找值
    if array[mid] < num:
        # 重置低位数
        low = mid+1
       # 如果中位数大于查找值 则锁定前半段
    elif array[mid] > num:
        # 重置低位数
        low = mid-1
    # 找到数字则打印该值下标 终止循环
    elif array[mid]==num:
        print('find it:',array[mid],'index:',mid)
        break

2、动态规划

每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,这种多阶段最优化决策解决问题的过程就称为动态规划。

背包问题:

背包问题是动态规划中中一个很经典的问题   假设张三要去野营,他准备了以下物品:

 

每样东西都有相应的价值,可呆呆的他在收拾背包时发现,他的背包 最大容量只有6斤,装不下所有的东西,只能从这堆东西中挑选 组合价值 最高的物品。

约束条件: 将背包的容量大小划分成不同容量大小的子背包,计算每个子背包的最大价值
物品重量不能超过当前背包容量,不可能将重量为5斤的物品放进容量为2斤的背包里。

每个子问题取得一次物品,就不能再取相同的物品,要么这个要么这个,拿了就没
比如此时 背包容量为6斤,拿了一瓶水后 占用了背包容量3斤剩余容量为3斤 我要么再拿一本书和一件衣服(1+2),要么再拿食物和一部手机(2+1)等,不可能再去拿一瓶水 。

def main() -> list:
    items = [  									 # 物品项
        {"name": "水", "weight": 3, "value": 10},
        {"name": "书", "weight": 1, "value": 3},
        {"name": "食物", "weight": 2, "value": 9},
        {"name": "小刀", "weight": 3, "value": 4},
        {"name": "衣物", "weight": 2, "value": 5},
        {"name": "手机", "weight": 1, "value": 10}
    ]
    max_capacity = 6                             # 约束条件为 背包最大承重为6
    dp = [[0] * (max_capacity + 1) for _ in range(len(items) + 1)]

    for row in range(1, len(items) + 1):         # row 代表行
        for col in range(1, max_capacity + 1):   # col 代表列
            weight = items[row - 1]["weight"]    # 获取当前物品重量
            value = items[row - 1]["value"]      # 获取当前物品价值
            if weight > col:                     # 判断物品重量是否大于当前背包容量
                dp[row][col] = dp[row - 1][col]  # 大于直接取上一次最优结果 此时row-1代表上一行
            else:
                # 使用内置函数max(),将上一次最优结果 与 当前物品价值+剩余空间可利用价值 做对比取最大值
                dp[row][col] = max(value + dp[row - 1][col - weight], dp[row - 1][col])
    return dp


dp = main()
for i in dp:        # 打印数组
    print(i)

print(dp[-1][-1])       # 打印最优解的价值和

3、回溯算法 

回溯法不同于动态规划。使用回溯法的关键是生成解空间,该问题的解空间是一个子集树,以深度优先的方式向下搜索判断,对于不符合条件的,采用剪枝函数直接结束本条路的循环。以节省时间。

输出一个数组中所有长度为k的组合。

def backtrack(combination, start, k):
    if len(combination) == k:  # 终止条件,找到一个长度为k的组合
        print(combination)
        return
    for i in range(start, len(arr)):
        combination.append(arr[i])  # 做出选择
        backtrack(combination, i + 1, k)  # 递归进入下一层,并从下一位置开始选择
        combination.pop()  # 撤销选择

arr = [1, 2, 3, 4, 5]
k = 3
backtrack([], 0, k)

4、分支界限法

分支界限法是一种用于求解最优化问题的算法。它通过将搜索空间划分为多个分支,并针对每个分支应用启发式策略来减少搜索空间,以便更快地找到最优解。

0-1背包问题  如何在给定的背包容量下,选择一组物品放入背包,以使得物品的总价值最大化。每件物品只能选择放入背包(即取 0 个或 1 个),不能切割物品。

class Item:
    def __init__(self, weight, value):
        self.weight = weight  # 物品重量
        self.value = value    # 物品价值

def branch_and_bound_knapsack(items, capacity):
    n = len(items)
    items.sort(key=lambda x: x.value/x.weight, reverse=True)  # 按照单位价值降序排序
    curr_weight = 0  # 当前背包重量
    curr_value = 0   # 当前背包价值
    best_value = 0   # 最优解的背包价值

    def bound(node):
        nonlocal curr_weight, curr_value, best_value

        if node.level >= n:
            return 0

        # 背包容量剩余不能放下任何一个完整的物品
        if curr_weight + items[node.level].weight > capacity:
            return 0

        # 能够放下整个物品时,更新当前背包重量和价值
        curr_weight += items[node.level].weight
        curr_value += items[node.level].value

        # 当前背包价值超过了最优解时,回溯
        if curr_value > best_value:
            curr_weight -= items[node.level].weight
            curr_value -= items[node.level].value
            return 0

        # 计算对于下一级节点的期望上界
        bound_value = node.value + (capacity - curr_weight) * items[node.level].value / items[node.level].weight

        # 更新最优解
        if bound_value > best_value:
            best_value = bound_value

        # 返回子问题的期望上界
        return bound_value

    class Node:
        def __init__(self, level, value):
            self.level = level  # 当前层级
            self.value = value  # 到达该层的背包价值

    queue = [Node(0, 0)]  # 用于存放待处理的节点队列
    while queue:
        node = queue.pop(0)  # 取出队列中的节点进行处理

        # 左子节点:不放入背包
        queue.append(Node(node.level + 1, node.value))

        # 右子节点:放入背包
        value = node.value + items[node.level].value  # 新的背包价值
        if value > best_value:  # 只有当该节点的目标函数值大于当前最优解时才进行处理
            best_value = value
            if node.level + 1 < n:
                queue.append(Node(node.level + 1, value))

    return best_value

items = [
    Item(2, 10),
    Item(5, 20),
    Item(3, 15),
    Item(7, 25),
    Item(4, 12)
]
capacity = 10

best_value = branch_and_bound_knapsack(items, capacity)
print("最优解的背包价值:", best_value)

5、贪心算法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值