Project Euler Problem 51

解法

0から9までの数値と'*'のみを用いて文字列を生成し,それの'*'を置き替えた時の素数の個数をチェックしていく.

  • '*'が含まれているかどうか
  • 最後の桁が奇数かどうか

で若干の枝刈りをするだけで一分に収まった.
素数判定にミラーラビン素数判定法を用いているが,篩を用いて全生成してから調べた方が早かったかもしれない.

実装(Visual Basic.NET)

Imports System
Imports System.IO
Imports System.Text
Imports System.Collections
Imports System.Collections.Generic
Imports System.Math
Imports System.Diagnostics

Public Class Algorithm
    Public Shared Function Mod_Pow(ByVal a As Long, ByVal n As Long, ByVal M As Long) As Long
        If n = 0 Then Return 1 Mod M
        Dim Res As Long = Mod_Pow((a * a) Mod M, Int(n / 2), M)
        If n And 1 Then Res = (Res * a) Mod M
        Return Res
    End Function
    Public Shared Function Miller_Rabin(ByVal n As Long) As Boolean
        If n = 2 Then Return True
        If (n Mod 2) = 0 Or n <= 1 Then Return False

        Dim i As Integer = 0, a As Integer() = New Integer() {2, 7, 61, -1}, r As Integer, s As Long = 0, d As Long, x As Long
        d = n - 1
        Do While (d Mod 2) = 0
            s += 1 : d >>= 1
        Loop
        Do While a(i) <> -1 And a(i) < n
            x = Mod_Pow(a(i), d, n)
            If x <> 1 Then
                For r = 0 To s - 1
                    If x = n - 1 Then Exit For
                    x = (x * x) Mod n
                Next
                If r = s Then Return False
            End If
            i += 1
        Loop
        Return True
    End Function
End Class

Module Module1
    '*を数値に置き替えたときに何個素数が出来るか
    Public Function Check(ByVal Value As String) As Integer
        Check = 0
        For i As Integer = 0 To 9
            Check = Check - Algorithm.Miller_Rabin(Long.Parse(Value.Replace("*", i.ToString)))
        Next
    End Function
    Public Target As String
    Public L As Integer
    Public Answer As String
    'Nは1からLの数値
    Public Sub Solve(ByVal N As Integer)
        If N = L Then
            If Target.Contains("*"c) = False Then Return
            For i As Integer = 1 To 9 Step 2
                If i = 5 Then Continue For

                Mid(Target, N, 1) = i.ToString
                Solve(N + 1)
            Next
        ElseIf N = L + 1 Then
            If Check(Target) = 8 Then
                Console.WriteLine("{0}:{1}", Target, Check(Target))
                For i As Integer = 0 To 9
                    If Answer = "" Then
                        If Algorithm.Miller_Rabin(Long.Parse(Target.Replace("*", i.ToString))) Then
                            Answer = Target.Replace("*", i.ToString)
                        End If
                    End If
                Next
            End If
        Else
            For i As Integer = 0 To 9
                If N = 1 And i = 0 Then Continue For
                Mid(Target, N, 1) = i.ToString
                Solve(N + 1)
            Next
            Mid(Target, N, 1) = "*"
            Solve(N + 1)
        End If
    End Sub
    Sub Main()
        Dim TimeCounter As New Stopwatch
        TimeCounter.Start()

        Answer = ""
        For i As Integer = 1 To 19
            L = i
            Target = New String(" ", L)
            Solve(1)
            If Answer <> "" Then Exit For
        Next
        L = 6

        TimeCounter.Stop()


        Console.WriteLine("----")
        Console.WriteLine("Answer:{0}", Answer)
        Debug.WriteLine("Answer:{0}", Answer)
        Console.WriteLine("Calculate Time:{0}sec", TimeCounter.ElapsedMilliseconds / 1000)

        '-----
        Console.WriteLine()
        Console.WriteLine("Press Any Key.")
        Console.ReadKey()
    End Sub
End Module