递归算法:列出正整数1到32和值为100的所有组合

一个典型的枚举问题,并不复杂。本文给出一个 Fortran 代码。
组合数量为:238905 个;运行耗时为:50 毫秒。

算法要点:
A. 确定组合的最大数量。按照最小数组成,用等差数列求和来预估:ia(ia+1)/2 = kmia² < ia²+ia = 2kmia < sqrt(2*km)。
B. 计算并传递和值累加的中间值 b,大于 km 的,提前退出本层递归,减少重复计算,提高速度。
C. 保存组合的数组 a 设置为公共变量,不在递归过程中传递。

Fortran 代码:


$freeform

! 递归枚举:列出正整数1到32和值为100的所有组合
! 2023-08-22
! szw_sh@163.com
! CVF编译项:DF /Ox



module aa                                        ! 定义公共变量
   parameter(kk=32,km=100,ia=(km*2)**0.5)        ! 常数:kk,最大数;km,和值;ia,最大个数
   integer a(0:ia)                               ! 数组:a,保存组合
   data m/0/
end module



use aa                                           ! 主程序

a=0                                              ! a赋初值
call cc(0,1)                                     ! 调用递归主程序cc
k=log10(m*1.0)+1
write(*,'(/5x,a,i<k>)') 'total = ',m             ! 输出组合的总数

end



recursive subroutine cc(b,n)                     ! 子程序,递归枚举

use aa
integer b                                        ! b用于传递和值计算的中间值,减少重复运算

do i=a(n-1)+1,kk                                 ! 可用数从a(n-1)+1开始

  a(n)=i                                         ! 赋值a(n)
  k=b+i                                          ! 计算和值

  if(k.gt.km) then                               ! 和值大于km,跳出本层递归
    exit
  else if(k.eq.km) then                          ! 和值相符,计数、输出
    m=m+1
    write(*,'(i10.6,a,<ia>i3)') m,'   ==>  ',a(1:n)
  else
    if(n.lt.ia) call cc(k,n+1)                   ! 未达到ia层,继续递归
  end if

end do

end

附:计算结果
限于篇幅,只列出头尾部分


    000001   ==>    1  2  3  4  5  6  7  8  9 10 11 12 22
    000002   ==>    1  2  3  4  5  6  7  8  9 10 11 13 21
    000003   ==>    1  2  3  4  5  6  7  8  9 10 11 14 20
    000004   ==>    1  2  3  4  5  6  7  8  9 10 11 15 19
    000005   ==>    1  2  3  4  5  6  7  8  9 10 11 16 18
    000006   ==>    1  2  3  4  5  6  7  8  9 10 12 13 20
    000007   ==>    1  2  3  4  5  6  7  8  9 10 12 14 19
    000008   ==>    1  2  3  4  5  6  7  8  9 10 12 15 18
    000009   ==>    1  2  3  4  5  6  7  8  9 10 12 16 17
    000010   ==>    1  2  3  4  5  6  7  8  9 10 13 14 18
    000011   ==>    1  2  3  4  5  6  7  8  9 10 13 15 17
    000012   ==>    1  2  3  4  5  6  7  8  9 10 13 32
    000013   ==>    1  2  3  4  5  6  7  8  9 10 14 15 16
    000014   ==>    1  2  3  4  5  6  7  8  9 10 14 31
    000015   ==>    1  2  3  4  5  6  7  8  9 10 15 30
    000016   ==>    1  2  3  4  5  6  7  8  9 10 16 29
    000017   ==>    1  2  3  4  5  6  7  8  9 10 17 28
    000018   ==>    1  2  3  4  5  6  7  8  9 10 18 27
    000019   ==>    1  2  3  4  5  6  7  8  9 10 19 26
    000020   ==>    1  2  3  4  5  6  7  8  9 10 20 25
    000021   ==>    1  2  3  4  5  6  7  8  9 10 21 24
    000022   ==>    1  2  3  4  5  6  7  8  9 10 22 23
    000023   ==>    1  2  3  4  5  6  7  8  9 11 12 13 19
    000024   ==>    1  2  3  4  5  6  7  8  9 11 12 14 18
    000025   ==>    1  2  3  4  5  6  7  8  9 11 12 15 17
    000026   ==>    1  2  3  4  5  6  7  8  9 11 12 32
    000027   ==>    1  2  3  4  5  6  7  8  9 11 13 14 17
    000028   ==>    1  2  3  4  5  6  7  8  9 11 13 15 16
    000029   ==>    1  2  3  4  5  6  7  8  9 11 13 31
    000030   ==>    1  2  3  4  5  6  7  8  9 11 14 30
    000031   ==>    1  2  3  4  5  6  7  8  9 11 15 29
    000032   ==>    1  2  3  4  5  6  7  8  9 11 16 28
    000033   ==>    1  2  3  4  5  6  7  8  9 11 17 27
    000034   ==>    1  2  3  4  5  6  7  8  9 11 18 26
    000035   ==>    1  2  3  4  5  6  7  8  9 11 19 25
    000036   ==>    1  2  3  4  5  6  7  8  9 11 20 24
    000037   ==>    1  2  3  4  5  6  7  8  9 11 21 23
    000038   ==>    1  2  3  4  5  6  7  8  9 12 13 14 16
    000039   ==>    1  2  3  4  5  6  7  8  9 12 13 30
    000040   ==>    1  2  3  4  5  6  7  8  9 12 14 29
    000041   ==>    1  2  3  4  5  6  7  8  9 12 15 28
    000042   ==>    1  2  3  4  5  6  7  8  9 12 16 27
    000043   ==>    1  2  3  4  5  6  7  8  9 12 17 26
    000044   ==>    1  2  3  4  5  6  7  8  9 12 18 25
    000045   ==>    1  2  3  4  5  6  7  8  9 12 19 24
    000046   ==>    1  2  3  4  5  6  7  8  9 12 20 23
    000047   ==>    1  2  3  4  5  6  7  8  9 12 21 22
    000048   ==>    1  2  3  4  5  6  7  8  9 13 14 28
    000049   ==>    1  2  3  4  5  6  7  8  9 13 15 27
    000050   ==>    1  2  3  4  5  6  7  8  9 13 16 26
    000051   ==>    1  2  3  4  5  6  7  8  9 13 17 25
    000052   ==>    1  2  3  4  5  6  7  8  9 13 18 24
    000053   ==>    1  2  3  4  5  6  7  8  9 13 19 23
    000054   ==>    1  2  3  4  5  6  7  8  9 13 20 22
    000055   ==>    1  2  3  4  5  6  7  8  9 14 15 26

    ......         ........................
    
    238870   ==>   20 21 27 32
    238871   ==>   20 21 28 31
    238872   ==>   20 21 29 30
    238873   ==>   20 22 26 32
    238874   ==>   20 22 27 31
    238875   ==>   20 22 28 30
    238876   ==>   20 23 25 32
    238877   ==>   20 23 26 31
    238878   ==>   20 23 27 30
    238879   ==>   20 23 28 29
    238880   ==>   20 24 25 31
    238881   ==>   20 24 26 30
    238882   ==>   20 24 27 29
    238883   ==>   20 25 26 29
    238884   ==>   20 25 27 28
    238885   ==>   21 22 25 32
    238886   ==>   21 22 26 31
    238887   ==>   21 22 27 30
    238888   ==>   21 22 28 29
    238889   ==>   21 23 24 32
    238890   ==>   21 23 25 31
    238891   ==>   21 23 26 30
    238892   ==>   21 23 27 29
    238893   ==>   21 24 25 30
    238894   ==>   21 24 26 29
    238895   ==>   21 24 27 28
    238896   ==>   21 25 26 28
    238897   ==>   22 23 24 31
    238898   ==>   22 23 25 30
    238899   ==>   22 23 26 29
    238900   ==>   22 23 27 28
    238901   ==>   22 24 25 29
    238902   ==>   22 24 26 28
    238903   ==>   22 25 26 27
    238904   ==>   23 24 25 28
    238905   ==>   23 24 26 27

     total = 238905
     

折返线

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值