分治策略:解决问题的典型策略,分而治之

  • 将问题分为若干更小规模的部分
  • 通过解决每一个小规模部分问题,并将结果汇总得到原问题的解

递归算法与分治策略

  • 递归三定律
  • 体现了分支策略
  • 应用相当广泛
    • 排序
    • 查找
    • 遍历
    • 求值等

优化问题

  • 计算机科学中许多算法都是为了找到某些问题的最优解

    • 两点之间最短路径
    • 能最好匹配一系列点的直线
    • 满足一定条件的最小集合

经典案例:找零兑换

贪心策略

  • 兑换最少个数的硬币
  • 贪心策略及失效
    • 63=252+101+1*3
    • 63=21*3

递归解法

  • 步骤

    • 确定基本结束条件

      需要兑换的找零,面值正好等于某种硬币
    • 减少问题规模

      对每种硬币尝试一次

  • 低效代码
import time

def recMC(coinValueList, change):
minCoins = change
if change in coinValueList:
return 1
else:
for i in [c for c in coinValueList if c <= change]:
numCoins = 1+recMC(coinValueList, change-i)
if numCoins < minCoins:
minCoins = numCoins
return minCoins if __name__ == "__main__":
print(time.clock())
print(recMC([1, 5, 10, 25], 63))
print(time.clock())

memoization 记忆化/函数值缓存

  • 优化

    • 消除重复计算

      用一个表将计算过的中间结果保存起来,在计算之前查表看看是否已经计算过

      • 有,直接返回最优解
      • 无,进行递归调用
    import time
    def recMC(coinValueList, change, knowResults):
    minCoins = change
    if change in coinValueList:
    knowResults[change] = 1
    return 1
    elif knowResults[change] > 0:
    return knowResults[change]
    else:
    for i in [c for c in coinValueList if c <= change]:
    numCoins = 1+recMC(coinValueList, change-i, knowResults)
    if numCoins < minCoins:
    minCoins = numCoins
    knowResults[change] = minCoins
    return minCoins if __name__ == "__main__":
    meno = [0]*64
    print(time.clock())
    print(recMC([1, 5, 10, 25], 63, meno))
    print(time.clock())
    print(meno) >>>
    2e-07
    6
    0.0061154
    [0, 1, 0, 0, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 3, 4, 5, 6]

动态规划解法

  • 步骤

    • 从最简单的“1分钱找零”的最优解开始,逐步狄加上去,直到我们需要的找零钱数
    • 在找零递加的过程中,一直加到求解找零钱数,自然得到最优解
    • 递加的过程能保持最优解的关键是,其依赖于更少钱数最优解的简单计算,而更少钱数的最优解已经得到了
    • 问题的最优解包含了更小规模子问题的最优解。

      这是一个最优化问题能够用动态规划策略解决的必要条件
  • 思想

    • 从最简单的情况开始到达所需找零的循环
    • 每一步都依靠以前的最优解来得到本步骤的最优解,直到得到答案
  • 代码实现

def dpMakeChange(coinValueList, change, minCoins, coinUsed):
# 1.从一分钱到change逐个计算最少硬币数
for cents in range(1, change+1):
coinCounts = cents
newCoin = 1
# 2.减去每个硬币,向后查最少硬币数,同时记录总的最少数
for j in [c for c in coinValueList if c <= cents]:
if minCoins[cents-j]+1 < coinCounts:
coinCounts = minCoins[cents-j]+1
newCoin = j
# 3.得到当前最少硬币数,记录到表中
minCoins[cents] = coinCounts
coinUsed[cents] = newCoin return minCoins[change] def printCoins(coinUsed, change):
coin = change
while coin > 0:
thisCoin = coinUsed[coin]
print(thisCoin)
coin = coin-thisCoin if __name__ == "__main__":
amnt=63
clist=[1, 5, 10, 21, 25]
coinUsed=[0]*(amnt+1)
coinCount=[0]*(amnt+1)
print("Making change for",amnt,"require",dpMakeChange(clist, amnt, coinCount,coinUsed),"coins")
print("They are:")
printCoins(coinUsed, amnt)
print("The used list is as follows:")
print(coinUsed) >>>
Making change for 63 require 3 coins
They are:
21
21
21
The used list is as follows:
[0, 1, 1, 1, 1, 5, 1, 1, 1, 1, 10, 1, 1, 1, 1, 5, 1, 1, 1, 1, 10, 21, 1, 1, 1, 25, 1, 1, 1, 1, 5, 10, 1, 1, 1, 10, 1, 1, 1, 1, 5, 10, 21, 1, 1, 10, 21, 1, 1, 1, 25, 1, 10, 1, 1, 5, 10, 1, 1, 1, 10, 1, 10, 21]

博物馆大盗问题

  • 动态规范代码
def calcTreasure1():
"""动态规划宝物价值最大化"""
# 宝物价值和重量
tr = [
None,
{'w': 2, 'v': 3},
{'w': 3, 'v': 4},
{'w': 4, 'v': 8},
{'w': 5, 'v': 8},
{'w': 9, 'v': 10}
] # 达到最大承重
max_w = 20 # 初始化二位表格m[(i,w)]
# 表示前i个宝物中,最大重量w的组合,所得到的最大价值
# 当i什么都不取,或w上限为0,价值均为0
m = {(i, w): 0 for i in range(len(tr))
for w in range(max_w+1)}
#逐个填写二维表格
for i in range(1,len(tr)):
for w in range(1,max_w+1):
if tr[i]['w']>w:
m[(i,w)]=m[(i-1,w)]
else:
m[(i,w)]=max(
m[(i-1,w)],
(m[(i-1,w-tr[i]['w'])]+tr[i]['v'])
)
# 输出结果
print(m)
print(m[(len(tr)-1,max_w)]) if __name__ == "__main__":
calcTreasure1()
  • 递归解法
# 宝物价值和重量
tr = {(2, 3), (3, 4), (4, 8), (5, 8), (9, 10)}
# 达到最大承重
max_w = 20 # 初始化二位表格m
# key是(宝物组合,最大重量),values是最大重量
m = {} def thief(tr, w):
if tr == set() or w == 0:
m[tuple(tr), w] = 0
return 0
elif (tuple(tr), w) in m:
return m[tuple(tr), w]
else:
vmax = 0
for t in tr:
if t[0] <= w:
# 逐个从集合中去掉某个宝物,递归调用
# 选出所有价值中的最大值
v = thief(tr-{t}, w-t[0])+t[1]
vmax = max(vmax, v)
m[tuple(tr), w] = vmax
#print("%2d ---- %2d " % (vmax,w),tr)
return vmax print(thief(tr, max_w))

【数据结构与算法Python版学习笔记】递归(Recursion)——优化问题与策略的更多相关文章

  1. 【数据结构与算法Python版学习笔记】引言

    学习来源 北京大学-数据结构与算法Python版 目标 了解计算机科学.程序设计和问题解决的基本概念 计算机科学是对问题本身.问题的解决.以及问题求解过程中得出的解决方案的研究.面对一 个特定问题,计 ...

  2. 【数据结构与算法Python版学习笔记】目录索引

    引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...

  3. 【数据结构与算法Python版学习笔记】递归(Recursion)——定义及应用:分形树、谢尔宾斯基三角、汉诺塔、迷宫

    定义 递归是一种解决问题的方法,它把一个问题分解为越来越小的子问题,直到问题的规模小到可以被很简单直接解决. 通常为了达到分解问题的效果,递归过程中要引入一个调用自身的函数. 举例 数列求和 def ...

  4. 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链

    散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...

  5. 【数据结构与算法Python版学习笔记】树——相关术语、定义、实现方法

    概念 一种基本的"非线性"数据结构--树 根 枝 叶 广泛应用于计算机科学的多个领域 操作系统 图形学 数据库 计算机网络 特征 第一个属性是层次性,即树是按层级构建的,越笼统就越 ...

  6. 【数据结构与算法Python版学习笔记】算法分析

    什么是算法分析 算法是问题解决的通用的分步的指令的聚合 算法分析主要就是从计算资源的消耗的角度来评判和比较算法. 计算资源指标 存储空间或内存 执行时间 影响算法运行时间的其他因素 分为最好.最差和平 ...

  7. 【数据结构与算法Python版学习笔记】基本数据结构——列表 List,链表实现

    无序表链表 定义 一种数据项按照相对位置存放的数据集 抽象数据类型无序列表 UnorderedList 方法 list() 创建一个新的空列表.它不需要参数,而返回一个空列表. add(item) 将 ...

  8. 【数据结构与算法Python版学习笔记】图——骑士周游问题 深度优先搜索

    骑士周游问题 概念 在一个国际象棋棋盘上, 一个棋子"马"(骑士) , 按照"马走日"的规则, 从一个格子出发, 要走遍所有棋盘格恰好一次.把一个这样的走棋序列 ...

  9. 【数据结构与算法Python版学习笔记】树——利用二叉堆实现优先级队列

    概念 队列有一个重要的变体,叫作优先级队列. 和队列一样,优先级队列从头部移除元素,不过元素的逻辑顺序是由优先级决定的. 优先级最高的元素在最前,优先级最低的元素在最后. 实现优先级队列的经典方法是使 ...

随机推荐

  1. kubernetes 安装 ingress controller

    文章链接 ingress-nginx ingress 官方网站 ingress 仓库地址 ingress-nginx v1.0 最新版本 v1.0 适用于 Kubernetes 版本 v1.19+ ( ...

  2. 你的 JVM 基础“大厦”稳健吗?

    [从 1 开始学 JVM 系列] JVM 对于每位 Java 语言编程者来说无疑是"重中之重",尽管我们每天都在与它打交道,却很少来审视它.了解它,慢慢地,它成为了我们" ...

  3. C#新版本风格(NetCore)项目文件

    在VisualStudio中创建NetCore以上版本的项目,使用的都是新版本风格的项目文件. 和旧版本.NetFramework版本的项目文件区别: 双击项目可直接打开csproj文件进行编辑配置 ...

  4. [考试总结]noip模拟40

    最近真的是爆炸啊... 到现在还是有不少没改出来.... 所以先写一下 \(T1\) 的题解.... 送花 我们移动右端点,之后我们用线段树维护全局最大值. 之后还要记录上次的位置和上上次的位置. 之 ...

  5. 百度云网速慢?普通VIP也限速?用户激励措施太套路?Pandownload被举报?这些统统没关系,我们自己搭建一个私人云盘服务器

    前言 前几天醒来后,照例耍手机看新闻.在疫情如此严重的档口,一则小小的新闻引起了我内心小小的波动:Pandownload作者被举报了....心里第一件事就是可惜了我盘上的那N多个T的小电影了,&quo ...

  6. python3 爬虫五大模块之五:信息采集器

    Python的爬虫框架主要可以分为以下五个部分: 爬虫调度器:用于各个模块之间的通信,可以理解为爬虫的入口与核心(main函数),爬虫的执行策略在此模块进行定义: URL管理器:负责URL的管理,包括 ...

  7. Jwt的新手入门教程

    Jwt的新手入门教程 1.Jwt究竟是什么东东? ​ 先贴官网地址:JSON Web Tokens - jwt.io ​ ​ 再贴官方的定义: What is JSON Web Token? JSON ...

  8. 做一个U盘的学习路线

    最近想研究一个U盘,然后顺便熟悉一下USB协议.因为USB协议比较复杂, 常用的复杂外设除了WiFi,Ethernet,SDIO和USB这些就是USB了,学习USB的时候肯定要拿一个东西下手,所以简单 ...

  9. php在类中使用回调函数 如array_map

    <?php class foo {   var $var;   function bar() {      array_map(array($this, "baz"), ar ...

  10. Linux下Nodejs安装(完整详细)转

    Linux下安装有两种方式,一个是下载源码make编译安装. 另外一种是比较推荐的,直接下载编译好的二进制,官方比较推荐后者. //Linux 64bit version wget --no-chec ...