.net Project Euler 76-列出给定数量的所有分区

.net Project Euler 76-列出给定数量的所有分区,.net,vb.net,numbers,.net,Vb.net,Numbers,这听起来像是: “一百可以用多少种不同的方式写成至少两个正整数的和?” 几天来,我一直在努力解决这个问题,尝试用不同的方法解决问题,对于小数字(那些容易检查的数字)得到的结果基本相同。最后,我给出了一个算法,该算法按字母顺序降序(从“N-1+1”开始)列出给定数字的所有分区。用VB.NET编写: Dim ub As Integer = 6 Dim wayCount As Integer = 0 For n = ub - 1 To 1 Step -1 'init value array (fi

这听起来像是: “一百可以用多少种不同的方式写成至少两个正整数的和?”

几天来,我一直在努力解决这个问题,尝试用不同的方法解决问题,对于小数字(那些容易检查的数字)得到的结果基本相同。最后,我给出了一个算法,该算法按字母顺序降序(从“N-1+1”开始)列出给定数字的所有分区。用VB.NET编写:

Dim ub As Integer = 6
Dim wayCount As Integer = 0
For n = ub - 1 To 1 Step -1
  'init value array (first combination)
  Dim s As New List(Of Integer)
  For m = 1 To ub \ n : s.Add(n) : Next
  Dim b As Integer = ub Mod n
  If b <> 0 Then s.Add(b)

  'from where to start decrementing
  Dim k As Integer = s.Count - 1
  While k > 0 And s(k) = 1 : k -= 1 : End While

  Do
    wayCount += 1 : Console.WriteLine(String.Join(" + ", s) & " = " & s.Sum)
    If s(k) = 1 Then k -= 1
    If k = -1 Then Exit Do
    s(k) -= 1
    s.Add(1)
  Loop While k >= 1
Next

Console.WriteLine("count=" & wayCount)
我研究了这些链接:

-提供数学解决方案,该解决方案不列出所有组合

-在python中,我无法读取/运行/理解


任何帮助都将不胜感激,提前感谢

您会说,“代码适用于数字1-6,包括数字1-6,在N=7时开始失败,缺少1个组合。”您应该在调试器中或手动对N=7的代码一行一行地进行检查。通过详细查看代码所做的工作,您将能够看到它遗漏了一个组合的位置。

您说,“代码适用于数字1-6,并且在N=7时开始失败,遗漏了一个组合。”对于N=7,您应该在调试器中或手动一次一行地遍历代码。通过详细了解您的代码正在执行的操作,您将能够看到它遗漏了组合的地方。

对于这个问题有一个相当准确的封闭式解决方案,信不信由你

哈代和拉马努扬公式:

                    e^(PI sqrt(2n/3))
            p(n) ~   -----------------
                        4n sqrt(3)
当n->无穷大时,距离会越来越近。 数学家拉德马赫提出了一个精确的公式,但它并不漂亮。

我建议你在维基百科和Mathworld上读一下

这是对这个问题的讨论


我不是说这些是解决这个问题的最好办法。事实上,对于n的合理小值来说,这是浪费时间,但看到这个解决方案以及更“面向计算机”的解决方案是很有趣的。

相信与否,这个问题有一个相当精确的封闭式解决方案

哈代和拉马努扬公式:

                    e^(PI sqrt(2n/3))
            p(n) ~   -----------------
                        4n sqrt(3)
当n->无穷大时,距离会越来越近。 数学家拉德马赫提出了一个精确的公式,但它并不漂亮。

我建议你在维基百科和Mathworld上读一下

这是对这个问题的讨论


我不是说这些是解决这个问题的最好办法。事实上,对于n的较小值来说,这是一种浪费时间的行为,但看到这种解决方案以及更“面向计算机”的解决方案是很有意思的。

正如所承诺的,这里有一些代码使用n以下的自然数对n(存储在ub中)进行分区,但不包括它。只要稍加修改,它就应该能够被任何函数分区,包括带有浮点输出的函数

基本思想是,对于分区中使用的每个值,我们都使用系数bucket,它是该值的乘数。在每一步中,我们要么将值充电到最大可用值,向左或向右移动,减小电流乘数,然后测试是否达到总和。一旦sum成功分区,wayCount将递增,结果将打印到屏幕上

这可能是一个有点脏的实现,但即使在问题的范围内(在我的机器上不到5分钟),它也能在合理的时间内工作,每秒生成数百万个分区。健康的批评总是受欢迎的

Dim ub As Integer = 10
Dim availableIncrements(ub - 2) As Integer
Dim weightCoefficients(ub - 2) As Integer
For i = 0 To ub - 2
  availableIncrements(i) = ub - i - 1
  weightCoefficients(i) = -1 'indicates that enumeration has not started yet
Next
Dim wayCount As Integer = 0

Dim pos, sum As Integer
pos = 0 : sum = 0
Do
  If weightCoefficients(pos) = -1 Then
    'when we came here first, charge coefficient to maximum available
    weightCoefficients(pos) = (ub - sum) \ availableIncrements(pos)
  ElseIf weightCoefficients(pos) > 0 Then
    'regular cycle: decrease by one
    weightCoefficients(pos) -= 1
  Else
    'return to previous bucket
    If pos = 0 Then Exit Do
    pos -= 1
    Continue Do
  End If

  'calculate current sum
  sum = 0
  For k = 0 To pos
    sum += availableIncrements(k) * weightCoefficients(k)
  Next
  'found combination
  If sum = ub And weightCoefficients(pos) > 0 Then
    wayCount += 1

    'printing to screen, remove when expecting many combinations
    Dim printList As New List(Of Integer)
    For i = 0 To pos 'which number to print
      For k = 1 To weightCoefficients(i) 'how many times to print a number
        printList.Add(availableIncrements(i))
      Next
    Next
    Console.WriteLine(String.Join(" + ", printList))

    'if we were in the last bucket and we just partitioned the number,
    'no need to go down and check all lower coefficients, instead move one column back.
    If pos = UBound(availableIncrements) Then
      pos -= 1
      Continue Do
    End If
  End If

  If pos < UBound(availableIncrements) Then
    pos += 1
    weightCoefficients(pos) = -1 'prepare to charge
  End If

  'this is something to keep you busy (so you know it's not hanging)
  'uncomment for long enumerations
  'If wayCount Mod 100000 = 0 Then Console.WriteLine(wayCount)
Loop

Console.WriteLine("count=" & wayCount)
Dim ub作为整数=10
Dim可用增量(ub-2)为整数
作为整数的Dim权重系数(ub-2)
对于i=0到ub-2
可用增量(i)=ub-i-1
权重系数(i)=-1'表示枚举尚未开始
下一个
Dim wayCount为整数=0
Dim pos,sum为整数
pos=0:sum=0
做
如果权重系数(pos)=-1,则
“当我们第一次来到这里时,电荷系数达到了可用的最大值
权重系数(pos)=(ub-sum)\n可用增量(pos)
如果其他权重系数(pos)>0,则
“正常周期:减少1
权重系数(pos)-=1
其他的
'返回到上一个桶
如果pos=0,则退出Do
位置-=1
继续做
如果结束
'计算当前金额
总和=0
对于k=0至位置
总和+=可用增量(k)*权重系数(k)
下一个
"找到组合",
如果sum=ub且权重系数(pos)>0,则
路数+=1
'打印到屏幕,需要多种组合时删除
Dim printList作为新列表(整数)
对于i=0到pos'要打印的号码
对于k=1到权重系数(i)‘打印一个数字需要多少次
打印列表。添加(可用增量(i))
下一个
下一个
Console.WriteLine(String.Join(“+”,printList))
“如果我们在最后一个桶里,我们只是划分了数字,
“不需要向下检查所有较低的系数,而是向后移动一列。
如果pos=UBound(可用增量),则
位置-=1
继续做
如果结束
如果结束
如果pos
正如所承诺的,这里有一些代码使用N以下的自然数对N(存储在ub中)进行分区,但不包括它。只要稍加修改,它就应该能够被任何函数分区,包括带有浮点输出的函数

基本思想是,对于分区中使用的每个值,我们都使用系数bucket,它是该值的乘数。在每一步中,我们要么将值充电到最大可用值,向左或向右移动,减小电流乘数,然后测试是否达到总和。一旦sum成功分区,wayCount将递增,结果将打印到屏幕上

这可能是个有点脏的小鬼