项目Euler 12,在vb.net中非常慢

时间:2017-11-07 16:45:30

标签: vb.net

所以你需要找到第一个有超过500个除数的三角形数。我找到了一种找到主要因子并将指数倍增的工作方法,但这需要很长时间。我怎样才能加快速度?

Function divisors(ByVal c As Long) As Integer
    Dim j, k As Integer
    Dim d As Long = c
    Dim factors As New List(Of Integer)
    For i As Long = 2 To c / 2 + 1
        If d Mod i = 0 Then
            If i Mod 2 = 0 And i <> 2 Then
                i = i / 2
            End If
            factors.Insert(k, i)
            d = d / i
            i = 2
            k += 1
        End If
    Next
    j = 1
    For i As Integer = 0 To factors.Count - 1
        j = j * factors(i)
    Next
    If j <> c Then
        factors.Add(2)
    End If
    factors.Add(factors.Max + 1)
    factors.Sort()
    Dim count, num1, totfactor As Integer
    Dim totfactors As New List(Of Integer)
    For Each num As Integer In factors
        If num1 <> num Then
            totfactor = count
            If totfactor <> 0 Then totfactors.Add(totfactor)
            totfactor = 0
        End If
        If num1 <> num Then count = 0
        For i As Integer = 0 To c
            If num = i Then
                count += 1
                Exit For
            End If
        Next

        num1 = num
    Next
    Dim total As Integer = 1
    For Each num As Integer In totfactors
        total = total * (num + 1)
    Next
    Return total
End Function
Sub Main()
    Dim number As Long = 153
    Dim pos As Integer = 18
    Do
        number = number + pos
        Console.WriteLine("number:" & number & " divisors:" & divisors(number))
        pos += 1
    Loop Until divisors(number) > 500
End Sub

1 个答案:

答案 0 :(得分:1)

Dim j, k As Integer
Dim d As Long = c
Dim factors As New List(Of Integer)
For i As Long = 2 To c / 2 + 1
    If d Mod i = 0 Then
        If i Mod 2 = 0 And i <> 2 Then
            i = i / 2
        End If
        factors.Insert(k, i)
        d = d / i
        i = 2
        k += 1
    End If
Next

factors.Insert(k, i)后面跟着k += 1,所以这是写factors.Add(i)的漫长道路。删除k,在您需要之前不要声明j

Dim d As Long = c
Dim factors As New List(Of Integer)
For i As Long = 2 To c / 2 + 1
    If d Mod i = 0 Then
        If i Mod 2 = 0 And i <> 2 Then
            i = i / 2
        End If
        factors.Add(i)
        d = d / i
        i = 2
    End If
Next

所有这些/都是浮点除法。使用\进行整数除法。转过Option Strict On。另外,简写,因为它很好。在i = 2末尾设置For并将i作为其循环变量也不会执行任何操作,因此请将其删除。

Dim d As Long = c
Dim factors As New List(Of Integer)
For i As Long = 2 To c \ 2 + 1
    If d Mod i = 0 Then
        If i Mod 2 = 0 And i <> 2 Then
            i \= 2
        End If
        factors.Add(i)
        d \= i
    End If
Next

我想最内层的If已被添加,因为您的代码没有获得素数因素,但这不是修复该错误的方法。暂时删除它。

Dim d As Long = c
Dim factors As New List(Of Integer)
For i As Long = 2 To c \ 2 + 1
    If d Mod i = 0 Then
        factors.Add(i)
        d \= i
    End If
Next

好的,现在我们已经陷入了获得素数因素(d \= i)和获得所有除数之间的中间位置。继续使用您的原始素因子计划:由于素数因子可以出现多次,因此您需要在分割数字时保持循环。

Dim d As Long = c
Dim factors As New List(Of Integer)

For i As Long = 2 To c \ 2 + 1
    While d Mod i = 0
        d \= i
        factors.Add(i)
    End While
Next

现在外循环可以提前停止很多次。

Dim d As Long = c
Dim i As Long = 2
Dim factors As New List(Of Integer)

While d >= i
    While d Mod i = 0
        d \= i
        factors.Add(i)
    End While

    i += 1
End While

您还可以使用i = 2在循环内部进行优化,然后从i = 3开始,并使用i += 2移动两次。不过,有一种更好的方式,我会去做。继续前进。

j = 1
For i As Integer = 0 To factors.Count - 1
    j = j * factors(i)
Next
If j <> c Then
    factors.Add(2)
End If

这......将所有因素重新组合在一起以撤消错误的固定修正。完全删除。

factors.Add(factors.Max + 1)
factors.Sort()

这是Add的内容是什么?此外,修复了错误后,它们已经排序。

Dim count, num1, totfactor As Integer
Dim totfactors As New List(Of Integer)
For Each num As Integer In factors
    If num1 <> num Then
        totfactor = count
        If totfactor <> 0 Then totfactors.Add(totfactor)
        totfactor = 0
    End If
    If num1 <> num Then count = 0
    For i As Integer = 0 To c
        If num = i Then
            count += 1
            Exit For
        End If
    Next

    num1 = num
Next
Dim total As Integer = 1
For Each num As Integer In totfactors
    total = total * (num + 1)
Next

我只是想跳过尝试理解这一部分。请放心,它非常慢,因为它从0循环到c以确认因子num是一个小于c的整数......总是如此。要根据其素数因子分数得到一个数的除数,请将一个加上每个素数的计数加起来:

Dim last As Integer = -1
Dim count As Integer = 0
Dim result As Integer = 1

For Each num As Integer In factors
    If num = last Then
        count += 1
    Else
        result *= count + 1
        last = num
        count = 1
    End If
Next

Return result * (count + 1)

所有这些都应该从Θ(N²)到O(N)的时间复杂度。您可以从此处获得答案,并注意它不需要Long。现在,将其折叠到其他循环中,因为您可以计算不同的素因子并同时找到它们:

Function Divisors(c As Integer) As Integer
    Dim d As Integer = c
    Dim i As Integer = 2
    Dim result As Integer = 1

    While d >= i
        Dim count As Integer = 1

        While d Mod i = 0
            d \= i
            count += 1
        End While

        result *= count
        i += 1
    End While

    Return result
End Function

最后,在divisorsConsole.WriteLine中调用Loop Until,停止加倍检查指定号码所需的时间:

Sub Main()
    Dim number As Integer = 153
    Dim pos As Integer = 18

    Do
        number += pos
        pos += 1
    Loop Until Divisors(number) > 500

    Console.WriteLine(number)
End Sub
相关问题