ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 3080|回复: 11

[原创] LAMBDA函数递归:m×n矩阵路径问题

[复制链接]

TA的精华主题

TA的得分主题

发表于 2022-12-6 22:32 | 显示全部楼层 |阅读模式
本帖最后由 shaowu459 于 2022-12-7 00:02 编辑

本帖主要来讨论递归解决的另外一个经典例子:m×n矩阵从左上角到右下角的路径问题。

有这样一个m行n列的矩阵,矩阵中的元素都是非负整数,从左上角往右下角移动时,每次只能移动到相邻的一个格子,并且每次只能向下或者向右移动。

下图是一个4×4的矩阵,最左上角的B2单元格只能移动到C2或B3,C3单元格只能移动到C4或者D3。也就是说,移动的时候,到达矩阵中的每个元素时只能从左侧或者上方的元素过来。如果用f(m,n)来表达元素的位置,则f(m,n)可能来自于f(m-1,n)或者f(m,n-1)。当m或n是第一行或第一列时,则只能来自于左侧的f(m,n-1)或者上方的f(m-1,n)
图片.png

那么,从左上角移动到右下角的路径一共有多少种呢?因为从左上角顶点开始走,所以从左上角到右下角,总共需要走n+m-2步,向下走总共需要m-1步,又因为每次都可以选择向下走,所以路径的总数就是C(n+m- 2,m- 1)种。
图片.png

m×n矩阵路径问题-超人.rar

20.44 KB, 下载次数: 31

评分

5

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-6 22:44 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 shaowu459 于 2022-12-7 00:05 编辑

我们做一个4×4的辅助区,在最左上角单元格输入以下公式,并向右、向下填充:
  1. =MIN(G1,F2)+B2
复制代码
图片.png

上述公式使每个单元格获得原数组的累加值,累加值结果是当前单元格左侧和上方累加值较小者和原数组中对应位置的合计。

例如下图H3单元格的5=MIN(H2单元格的4,G3单元格的5)+C3单元格的1。也就是按只能向下或向右的移动方式,移动到当前单元格所有路径中和的最小值。如此一直计算到最右下角的绿色单元格=12,也就意味着原矩阵从最左上角到最右下角所有路径上的合计值最小值是12。
图片.png

这个最小值12的路径可能有多条,下面展示一条路径:
图片.png

站在矩阵中任意单元格去看,到达该单元格的路径数量其实等于达到其左侧单元格和到达其上方单元格的路径数量合计。如下图,到达方框中的3只能从圆圈的1或5过来,因为到达圆圈1有2种路径(1-->4-->1和1-->3-->1),到达5只有一种路径(第一行1-->3-->5),所以到达方框的3共有2+1=3种路径。

归纳来说到达f(m,n)的路径条数=f(m,n-1)+f(m-1,n),当m=1或者n=1及m=n=1时需要特殊处理一下。
图片.png

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-6 23:16 | 显示全部楼层
本帖最后由 shaowu459 于 2022-12-6 23:18 编辑

根据上面的分析,明显可以看出求最终的路径总条数可以用递归来解决。我们定义fx如下:
  1. =LAMBDA(d,m,n,IF(m*n=1,1,IF(m=1,fx(d,1,n-1),IF(n=1,fx(d,m-1,1),fx(d,m-1,n)+fx(d,m,n-1)))))
复制代码
在任意单元格中输入以下公式即可获得矩阵从左上角到右下角的总路径数:
  1. =fx(A1:D4,4,4)
复制代码
图片.png

公式大致分析如下:
=LAMBDA(d,    初始参数矩阵
               m,    初始参数矩阵的行数
               n,     初始参数矩阵的列数
               IF(m*n=1,1,      如果m=n=1就是到最左上角单元格,返回1
                                 IF(m=1,fx(d,1,n-1),     如果到第1行了,就只能往做移动
                                                            IF(n=1,fx(d,m-1,1),     如果到第1列了,就只能往上移动
                                                                                        fx(d,m-1,n)+fx(d,m,n-1)))))  加和左侧和上方路径数量

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-6 23:25 | 显示全部楼层
同样的道理,我们可以定义gx来获取所有路径的具体情况:
  1. =LAMBDA(d,m,n,IF(m*n=1,@+d,IF(m=1,gx(d,1,n-1),IF(n=1,gx(d,m-1,1),VSTACK(gx(d,m-1,n),gx(d,m,n-1))))&"->"&INDEX(d,m,n)))
复制代码
图片.png

公式大致解读如下:

=LAMBDA(d,   初始参数矩阵
               m,   初始参数矩阵行数
               n,    初始参数矩阵列数
               IF(m*n=1,@+d,  如果m=n=1则返回矩阵左上角的值
                              IF(m=1,gx(d,1,n-1),  如果到第1行,只能向左走
                                         IF(n=1,gx(d,m-1,1),  如果到第1列,只能向上走
                                                    VSTACK(     非第1行第1列,则堆积上方和左侧结果
                                                                gx(d,m-1,n),  上方结果
                                                                gx(d,m,n-1)    左侧结果
                                                               )
                                              )
                                 )&"->"&INDEX(d,m,n)  记录以上的路径->当前的元素值
                  )
              )

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-6 23:31 | 显示全部楼层
本帖最后由 shaowu459 于 2022-12-6 23:47 编辑

定义tx,可以获得每条路径经过数字合计值的最小值(可能有多条最小值路径):
  1. =LAMBDA(d,m,n,IF(m*n=1,@+d,IF(m=1,tx(d,1,n-1),IF(n=1,tx(d,m-1,1),MIN(tx(d,m-1,n),tx(d,m,n-1))))+INDEX(d,m,n)))
复制代码
图片.png

公式与前两个公式大同小异:
=LAMBDA(d,
               m,
               n,
               IF(m*n=1,@+d,
                              IF(m=1,tx(d,1,n-1),
                                         IF(n=1,tx(d,m-1,1),
                                                    MIN(tx(d,m-1,n),tx(d,m,n-1))  取左侧和上方的合计值较小者
                                            )
                                 )+INDEX(d,m,n)   较小者加上当前矩阵的元素数值
                )
              )

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-6 23:40 | 显示全部楼层
本帖最后由 shaowu459 于 2022-12-7 00:08 编辑

4楼公式已经获得了所有路径,如果要求最小路径,就可以MAP函数将每个元素按分隔符拆分求和,然后再FILTER(路径数组,每个路径值合计=每个路径值合计数组的最小值)来筛选出来。我们也可以定一个一个dx来直接获得(忽略效率问题)最小值对应的各种路径:
  1. =LAMBDA(d,m,n,IF(m*n=1,@+d,IF(m=1,dx(d,1,n-1),IF(n=1,dx(d,m-1,1),LET(s,VSTACK(dx(d,m-1,n),dx(d,m,n-1)),t,MAP(s,LAMBDA(x,SUM(--TEXTSPLIT(x,"->")))),FILTER(s,t=MIN(t)))))&"->"&INDEX(d,m,n)))
复制代码
图片.png
=LAMBDA(d,
               m,
               n,
               IF(m*n=1,@+d,
                             IF(m=1,dx(d,1,n-1),
                                         IF(n=1,dx(d,m-1,1),
                                                    LET(s,VSTACK(dx(d,m-1,n),dx(d,m,n-1)),   堆积各种方案结果

                                                           t,MAP(s,LAMBDA(x,SUM(--TEXTSPLIT(x,"->")))),   将方案中数字拆分后求和
                                                           FILTER(s,t=MIN(t))   筛选数值最小的路径
                                                         )
                                             )
                                )&"->"&INDEX(d,m,n)   当前元素之前的最小路径并上当前元素
                   )
               )


TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-6 23:43 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 shaowu459 于 2022-12-6 23:49 编辑

文件已在1楼上传,递归公式根据算法不同写法应该有很多种,欢迎分享探讨。在Excel中解决类似问题,效率确实不太理想。矩阵稍微增大之后,比如说10×20的矩阵,Excel就计算不出来了,并且由于路径总数太大,也无法显示在工作表的有限行数内。所以,本帖也仅仅是练习使用递归解决问题的方法,如果真实需求使用,这些还得靠各种编程语言来高效率实现。

TA的精华主题

TA的得分主题

发表于 2022-12-7 10:04 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助

TA的精华主题

TA的得分主题

发表于 2022-12-9 16:13 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
太厉害了!!!

TA的精华主题

TA的得分主题

发表于 2022-12-12 12:51 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-27 21:18 , Processed in 0.049439 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表