Python非单向递归函数如何返回全部结果


Posted in Python onDecember 18, 2020

递归( recursion)是一种神奇的编程技巧,可以大幅简化代码,使之看起来更加简洁。然而递归设计却非常抽象,不容易掌握。通常,我们都是自上而下的思考问题, 递归则是自下而上的解决问题——这就是递归看起来不够直观的原因。

和递归相关的概念里,线性递归/非线性递归、单向递归/非单向递归,是非常重要的,要想掌握递归技术,就必须要深入理解。关于递归的基本概念,有兴趣的读者,可以参考我的博客《Python 递归算法指归》。今天,仅就背包问题谈非单向递归函数如何返回全部结果。

背包问题的背后,是世界七大数学难题之一,多项式复杂程度的非确定性问题。作为程序员,可以将该问题大致上理解为组合优化的问题。背包问题通常被这样描述:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,如何选择,才能使得物品的总价格最高。如果加上不同的限制和条件,背包问题可以衍生出很多变种。比如,下面这道题看起来和背包问题相去甚远,实质上仍然是一个典型的背包问题。

在一款英雄对战游戏中,玩家拥有m件装备和n位英雄,他可以给每一位英雄分配0件或多件装备,而不同的英雄拥有不同数目的装备时将获得不同的攻击力。玩家如何分配这m件装备,可以使得n个英雄获得的攻击力的和最大?以玩家拥有5件装备和3位英雄为例,下表共有3行6列,对应着3位英雄分别拥有从0到5件装备时的攻击力。

0件 1件 2件 3件 4件 5件
英雄1 0 1 3 5 7 9
英雄2 0 1 1 3 3 7
英雄3 0 3 4 5 6 7

即使不熟悉背包问题,也不难找到解题思路:

  • 找出所有可能的装备分配方案
  • 计算每一个方案的攻击值
  • 选择攻击值最大的分配方案

1. 找出所有可能的装备分配方案

找出将m件装备分配给n位英雄的所有方案是解决问题的核心。这里,循环嵌套是行不通的,因为嵌套层数是输入变量。递归是我想到的可行的方法。

>>> def bag(m, n, series=list()):
    if n == 1:
      for i in range(m+1):
        print(series+[i])
    else:
      for i in range(m+1):
        bag(m-i, n-1, series+[i])
  
>>> bag(3,2) # 将3件装备分配给2位英雄的全部方案
[0, 0]
[0, 1]
[0, 2]
[0, 3]
[1, 0]
[1, 1]
[1, 2]
[2, 0]
[2, 1]
[3, 0]

递归函数bag,打印出了将3件装备分配给2位英雄的全部方案。显然,这不是一个单向递归,因为在同一级有多次递归调用,这意味着递归过程有多次从递归出口走出。对于非单向递归,是不能使用return返回结果的。那么,如何让递归函数返回全部方案呢?请看下面的例子。

>>> def bag(m, n, result, series=list()):
 if n == 1:
 for i in range(m+1):
  result.append(series+[i])
  #print(result[-1])
 else:
 for i in range(m+1):
  bag(m-i, n-1, result, series+[i])

  
>>> result = list()
>>> bag(5, 3, result) # 将5件装备分配给3位英雄,共有56种分配方案
>>> len(result)
56
>>> result
[[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 0, 3], [0, 0, 4], [0, 0, 5], 
[0, 1, 0], [0, 1, 1], [0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 2, 0], 
[0, 2, 1], [0, 2, 2], [0, 2, 3], [0, 3, 0], [0, 3, 1], [0, 3, 2], 
[0, 4, 0], [0, 4, 1], [0, 5, 0], [1, 0, 0], [1, 0, 1], [1, 0, 2], 
[1, 0, 3], [1, 0, 4], [1, 1, 0], [1, 1, 1], [1, 1, 2], [1, 1, 3], 
[1, 2, 0], [1, 2, 1], [1, 2, 2], [1, 3, 0], [1, 3, 1], [1, 4, 0], 
[2, 0, 0], [2, 0, 1], [2, 0, 2], [2, 0, 3], [2, 1, 0], [2, 1, 1], 
[2, 1, 2], [2, 2, 0], [2, 2, 1], [2, 3, 0], [3, 0, 0], [3, 0, 1], 
[3, 0, 2], [3, 1, 0], [3, 1, 1], [3, 2, 0], [4, 0, 0], [4, 0, 1], 
[4, 1, 0], [5, 0, 0]]

上面的代码中,在调用递归函数之前,先创建一个全局的列表对象result,并作为参数传递给递归函数。递归调用结束后,全部的装备分配方案就保存在列表对象result中。

2. 计算每一个方案的攻击值

遍历56种分配方案,计算每一种方案的攻击力之和,保存到一个新的列表v中。p为3位英雄分别拥有从0到5件装备时的攻击力。

>>> p = [
 [0,1,3,5,7,9],
 [0,1,1,3,3,7],
 [0,3,4,5,6,7]
]
>>> v = list()
>>> for item in result:
    v.append(p[0][item[0]] + p[1][item[1]] + p[2][item[2]])
 
>>> v
[0, 3, 4, 5, 6, 7, 1, 4, 5, 6, 7, 1, 4, 5, 6, 3, 6, 7, 3,
 6, 7, 1, 4, 5, 6, 7, 2, 5, 6, 7, 2, 5, 6, 4, 7, 4, 3, 6, 
 7, 8, 4, 7, 8, 4, 7, 6, 5, 8, 9, 6, 9, 6, 7, 10, 8, 9]

3. 选择攻击值最大的分配方案

找出v列表最大值的序号,进而得到攻击力最大的装备分配方案。

>>> max(v)
10
>>> result[v.index(max(v))] 
[4, 0, 1]

最佳分配方案是第1位英雄持有4件装备,第2位英雄没有装备,第3位英雄持有1件装备,此时3位英雄的攻击力之和为最大,其值为10。

到此这篇关于Python非单向递归函数如何返回全部结果的文章就介绍到这了,更多相关Python非单向递归返回 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
使用python的chardet库获得文件编码并修改编码
Jan 22 Python
在Django中创建URLconf相关的通用视图的方法
Jul 20 Python
Python实现获取磁盘剩余空间的2种方法
Jun 07 Python
使用django-crontab实现定时任务的示例
Feb 26 Python
Python获取昨天、今天、明天开始、结束时间戳的方法
Jun 01 Python
python 多线程中子线程和主线程相互通信方法
Nov 09 Python
Python + OpenCV 实现LBP特征提取的示例代码
Jul 11 Python
如何查看Django ORM执行的SQL语句的实现
Apr 20 Python
Python Django form 组件动态从数据库取choices数据实例
May 19 Python
详解Python模块化编程与装饰器
Jan 16 Python
全网最详细的PyCharm+Anaconda的安装过程图解
Jan 25 Python
python如何构建mock接口服务
Jan 28 Python
python复合条件下的字典排序
Dec 18 #Python
python 监控服务器是否有人远程登录(详细思路+代码)
Dec 18 #Python
细说NumPy数组的四种乘法的使用
Dec 18 #Python
如何通过python检查文件是否被占用
Dec 18 #Python
python 实现端口扫描工具
Dec 18 #Python
Python-split()函数实例用法讲解
Dec 18 #Python
Python+Opencv实现把图片、视频互转的示例
Dec 17 #Python
You might like
PHP文件注释标记及规范小结
2012/04/01 PHP
使用phpstorm和xdebug实现远程调试的方法
2015/12/29 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
发布一个高效的JavaScript分析、压缩工具 JavaScript Analyser
2007/11/30 Javascript
JQUERY CHECKBOX全选,取消全选,反选方法三
2008/08/30 Javascript
input+select(multiple) 实现下拉框输入值
2009/05/21 Javascript
利用json获取字符出现次数的代码
2012/03/22 Javascript
js截取固定长度的中英文字符的简单实例
2013/11/22 Javascript
Jquery倒计时源码分享
2014/05/16 Javascript
JS使用ajax从xml文件动态获取数据显示的方法
2015/03/24 Javascript
简介AngularJS中使用factory和service的方法
2015/06/17 Javascript
JS 实现 ajax 异步浏览器兼容问题
2017/01/21 Javascript
Angular.js ng-file-upload结合springMVC的使用教程
2017/07/10 Javascript
基于vue中keep-alive缓存问题的解决方法
2018/09/21 Javascript
详解React服务端渲染从入门到精通
2019/03/28 Javascript
在Vue中使用icon 字体图标的方法
2019/06/14 Javascript
JS代码优化的8点建议
2020/02/04 Javascript
解决iview table组件里的 固定列 表格不自适应的问题
2020/11/13 Javascript
python读取文本中数据并转化为DataFrame的实例
2018/04/10 Python
pip安装py_zipkin时提示的SSL问题对应
2018/12/29 Python
django最快程序开发流程详解
2019/07/19 Python
Python用access判断文件是否被占用的实例方法
2020/12/17 Python
Spartoo瑞典:鞋子、包包和衣服
2018/09/15 全球购物
新闻系毕业生推荐信
2013/11/16 职场文书
服装店营销方案
2014/03/10 职场文书
四群教育工作实施方案
2014/03/26 职场文书
励志演讲稿600字
2014/08/21 职场文书
2014年扶贫工作总结
2014/11/18 职场文书
酒店前台岗位职责
2015/04/16 职场文书
2015年中学图书馆工作总结
2015/07/22 职场文书
分布式锁为什么要选择Zookeeper而不是Redis?看完这篇你就明白了
2021/05/21 Redis
浅析NIO系列之TCP
2021/06/15 Java/Android
go语言使用Casbin实现角色的权限控制
2021/06/26 Golang
java设计模式--建造者模式详解
2021/07/21 Java/Android
国产动画《万圣街》日语配音版制作决定!
2022/03/20 国漫
关于MySQL中explain工具的使用
2023/05/08 MySQL