• 最接近π值的5位分数的算法


    题目:

    求一个分数,分子5位数(第1位不是0),分母也是5位数(第1位不是0),分子和分母这10个数正好由0到9这10个数字组成(不缺也不重复)。求最接近π值的那个分数

    解法1(穷举法)

    Sub getit()
    Const num As Long = 3628800 ' 10!
    Dim tt As Single, i As Long, j As Long, k As Long, temp1 As Long, temp2 As Long, pi As Single, diff As Single, out As String, temp As String
    pi = 4 * Atn(1)
    diff = 1
    tt = Timer '开始计时
    For i = 0 To num - 1
    temp = 0
    temp1 = i
    For j = 2 To 10
    temp2 = temp1 Mod j + 1
    temp1 = temp1 / j
    temp = Left(temp, temp2 - 1) & j - 1 & Mid(temp, temp2)
    Next
    If temp Like "[3-9]####[1-3]####" Then
    temp1 = Val(Left(temp, 5))
    temp2 = Val(Right(temp, 5))
    If Abs(temp1 / temp2 - pi) < diff Then diff = Abs(temp1 / temp2 - pi):  out = temp1 & "/" & temp2
    End If
    Next
    MsgBox out & "用时 " & Timer - tt & " 秒!"
    End Sub

    最后结果:=85910/27346

    上述代码效率太低.

    解法2(穷举法)

    Sub Getit()
    Dim pi As Single, diff As Single, i As Long, j As Long, temp As Long, s() As Byte, n As Byte, result As String, tt As Single
    tt = Timer
    pi = 4 * Atn(1)
    diff = 1
        For i = 31425 To 98765
        ReDim s(9)
        For j = 1 To 5
        s(Mid(i, j, 1)) = 1
        Next
        If WorksheetFunction.Sum(s) = 5 Then
             temp = Fix(i / pi)
             For j = 1 To 5
               s(Mid(temp, j, 1)) = 1
             Next
            If WorksheetFunction.Sum(s) = 10 Then
                If Abs(i / temp - pi) < diff Then
                  diff = Abs(i / temp - pi)
                 result = i & "/" & temp
                End If
            End If
       End If
    Next
    MsgBox result, vbInformation, "总计用时" & Timer - tt & "秒!"
    End Sub

     解法3(递归法)(yier_fang提供,http://club.excelhome.net/dispbbs.asp?boardid=2&replyid=978209&id=262029&page=1&skin=0&Star=1)

     Dim lngFM As Long
        Dim lngFZ As Long
        Const PI = 3.1415926535
        Dim dbl As Double
        Dim kkk As Long
        Dim intCK As Integer
        Dim showW As Boolean
        Dim Unums As String
        Dim Lnums As String
       
       
    Sub cnft()
        Dim tm
        tm = Timer
        Application.ScreenUpdating = False
        kkk = 0: lngFM = 0: lngFZ = 0
        Unums = Cells(3, "H")
        Lnums = Cells(3, "I")
        dbl = 3.1415926535
        intCK = Cells(3, "F").Value
        showW = Cells(3, "E").Value
        If showW Then UserForm1.Show
        Call fs("", "")
        Cells(1, 2).Value = lngFZ
        Cells(2, 2).Value = lngFM
        If lngFM = 0 Then
            Cells(3, 2).Value = "无解"
        Else
            Cells(3, 2).Value = (lngFZ / lngFM)
        End If
        Cells(4, 2).Value = kkk
        UserForm1.Hide
        Application.ScreenUpdating = True
        Cells(5, 2) = Format((Timer - tm), "0.0000") & "秒"
    End Sub
    Sub fs(ByRef FM As String, ByRef FZ As String)
        kkk = kkk + 1
        If showW Then
            UserForm1.TextBox1.Text = "递归第..." & kkk & "...次"
            DoEvents
        End If
        Dim i, j As Long
        If Len(FM) = 0 Then
            For i = 1 To 9
                For j = 1 To 9
                    If i <> j Then
                        Call fs(CStr(i), CStr(j))
                    End If
                Next j
            Next i
        ElseIf Len(FM) < 5 Then
            If intCK = 1 Then
                If ((FZ - 1) / (FM + 1)) > PI Then Exit Sub
                If FM = 1 Then
                    If ((FZ + 1) / (FM)) < PI Then Exit Sub
                Else
                    If ((FZ + 1) / (FM - 1)) < PI Then Exit Sub
                End If
            ElseIf intCK = 2 Then
                '=======下面是手工的出口设置=========
                If FZ / FM < Lnums Then Exit Sub
                If FZ / FM > Unums Then Exit Sub
            End If
            For i = 0 To 9
                If InStr(FM & FZ, i) = 0 Then
                    For j = 0 To 9
                        If InStr(FM & FZ & i, j) = 0 Then
                            Call fs(FM & i, FZ & j)
                        End If
                    Next j
                End If
            Next i
               
        Else
           
            If Abs((FZ / FM) - PI) < dbl Then
                lngFM = FM
                lngFZ = FZ
                dbl = Abs((FZ / FM) - PI)
               
            End If
        End If
    End Sub

     解法4(递归法)(彭希仁提供:http://club.excelhome.net/dispbbs.asp?boardid=2&replyid=977506&id=262029&page=1&skin=0&Star=2)

    Public pi
    Public x
    Public y
    Public z
    Public k As Long
    Public st
    Sub peng()
        t = Timer
        pi = 4 * Atn(1)
        x = 10
        st = 0
        Call caii("", 0)
        MsgBox (y & "/" & z & "=" & y / z & "递归" & st & "次,耗时" & Timer - t & "秒")
    End Sub
    Sub caii(a, i)
        st = st + 1
        m = 0
        If i = 1 Then m = 3
        For j = m To 9
            If Not (a Like "*" & j & "*") Then
                If i + 1 = 5 Then
                    k = a & j
                    If k > 31415 Then
                     kp = Round(k / pi)
                        If Abs(k / kp - pi) < x Then
                            h = k & kp
                            For n = 0 To 9
                                If Not (h Like "*" & n & "*") Then Exit For
                            Next n
                            If n = 10 Then
                                x = Abs(k / kp - pi)
                                y = k
                                z = kp
                            End If
                        End If
                    End If
                Else
                    Call caii(a & j, i + 1)
                End If
            End If
        Next j
    End Sub

     解法5(回溯法)

    Sub getit(ByVal target As Single)   'target is a single number between 1~98765/10234
    Dim n As Byte, m As Byte
    Dim i As Integer, j As Integer, t As Integer, a(), fenmu As Long, fenzi As Long, max As Long, temp As String, result As Long
    m = 4: n = 9
    diff = 1
    tt = Timer
    max = int(98765/target)
    ReDim a(m)
    For i = 1 To m
    a(i) = -1
    Next
    Do
    a(t) = a(t) + 1
    If a(t) > n Then
    t = t - 1
    Else
    For i = 0 To t - 1
    If a(t) = a(i) Then Exit For
    Next
    If i = t Then
    If t = m Then
    fenmu = Join(a, "")
    fenzi = Round(fenmu * target)
    temp = fenzi & "/" & fenmu
    If Abs(fenzi / fenmu - target) < diff Then
    For j = 0 To 9
    If InStr(temp, j) = 0 Then Exit For
    Next
    If j = 10 Then diff = Abs(fenzi / fenmu - target): result = fenmu
    End If
    End If
    If t < m Then t = t + 1: a(t) = -1
    End If
    End If
    If fenmu > max Then Exit Do
    Loop Until t = -1
    Debug.Print "Target:     " & target & vbCrLf & "Result:     " & Round(result * target) & "/" & result & vbCrLf & "Error:      " & diff & vbCrLf & "Lapsetime:  " & Format(Timer - tt, "0.00000") & " seconds" & vbCrLf
    End Sub

    Sub macro1()
    getit Sqr(2)
    getit Sqr(3)
    getit Exp(1)
    getit 4 * Atn(1)
    getit 5.6789
    End Sub

    返回:

    Target:     1.414214
    Result:     95103/67248
    Error:      4.76071359769127E-07
    Lapsetime:  0.20313 seconds

    Target:     1.732051
    Result:     93820/54167
    Error:      1.03205265816492E-07
    Lapsetime:  0.13867 seconds

    Target:     2.718282
    Result:     87159/32064
    Error:      4.39718097983719E-07
    Lapsetime:  0.06445 seconds

    Target:     3.141593
    Result:     85910/27346
    Error:      1.79341409058684E-07
    Lapsetime:  0.04492 seconds

    Target:     5.6789
    Result:     95082/16743
    Error:      1.08244854411521E-05
    Lapsetime:  0.01563 seconds

  • 相关阅读:
    Spark:大数据的“电光石火”
    Android开发-取消程序标题栏或自定义标题栏
    Android中实现圆角矩形及半透明效果。
    Android中设定背景图片平铺。
    收到的电邮附件为Winmail.dat?
    Runas命令:能让域用户/普通User用户以管理员身份运行指定程序。
    AD域服务器|两台DC无法进行复制同步
    IIS服务器运行一段时间后卡死,且无法打开网站(IIS管理无响应,必须重启电脑)
    Outlook不能打开附件(提示:无法创建文件xx,请右键单击要在其中创建文件的文件夹..)
    点击自动显示/隐藏DIV代码。(简单实用)
  • 原文地址:https://www.cnblogs.com/fengju/p/6336293.html
Copyright © 2020-2023  润新知