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

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

递归算法与分治策略

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

优化问题

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

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

经典案例:找零兑换

贪心策略

  • 兑换最少个数的硬币
  • 贪心策略及失效
    • 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. SSH整合(二)

    SSH框架实现登录.新闻增删改查.树形菜单 项目结构 pom.xml 网不好不要一次引入太多,容易下不全 <project xmlns="http://maven.apache.org ...

  2. Python常见问题 - python3 使用requests发送HTTPS请求报certificate verify failed 错误

    当你使用 requests 发送HTTPS请求时 requests.get(url, parmas=parmas, headers=header, cookies=cookie) 出现了以下错误 HT ...

  3. Junit5快速入门指南-3

    Fixtures 是测试中非常重要的一部分.他们的主要目的是建立一个固定/已知的环境状态以确保 测试可重复并且按照预期的方式运行.比如在app测试中 基类@BeforeClass 配置初始化,初始化d ...

  4. npm 淘宝镜像与官方源 切换

    1.临时使用 npm --registry https://registry.npm.taobao.org install 包名 2.永久设置为淘宝镜像 npm config set registry ...

  5. JDBC基础和使用

    内存泄漏意思就是内存越来越少了,因为垃圾太多: 线程泄露就是线程池中线程越来越少,执行过程中异常,没有返回给线程池,线程池中线程越来越少: 一.概念 二.快速入门 三.JDBC各个类详解 1.driv ...

  6. 模板引挚 jade ejs

    // asl sum翡翠 后台使用如下: const jade = require('jade') //pretty 美化的意思,指的是渲染的布局会美化   2020-2-15 var str = j ...

  7. Docker安装flink及避坑指南

    Docker安装flink 导航 无处不在的大数据 安装flink 拉取flink镜像 编写docker-compose.yml 生成启动 查看安装效果 常见坑及解决方案 问题1 问题2 参考   本 ...

  8. 异步servlet的原理探究

    异步servlet是servlet3.0开始支持的,对于单次访问来讲,同步的servlet相比异步的servlet在响应时长上并不会带来变化(这也是常见的误区之一),但对于高并发的服务而言异步serv ...

  9. Jenkins 进阶篇 - 任务关联

    有时候我们的一个任务里面会进行很多的步骤,例如构建一个后端的 Java 服务,可能会有代码静态扫描,静态扫描通过后会打包成 jar 或者 war 文件,打包成功后可能还会对制品进行存档备份,然后可能会 ...

  10. PHP 一个树为另一棵树的子结构 [TO BE CONTINUED]

    输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) <?php class TreeNode { private $val; private $left; ...