Advertisement
Guest User

Untitled

a guest
Jul 24th, 2015
183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 3.28 KB | None | 0 0
  1. import scala.annotation.tailrec
  2. import scala.collection.mutable
  3.  
  4. object PrimeFrog {
  5.   def primesUpTo(n: Int): Set[Int] = {
  6.     // sieve of eratosthenes
  7.     val candidatePrimes = mutable.BitSet.empty ++ (2 to n)
  8.     val limit = math.sqrt(n).toInt
  9.     for (i <- 2 to limit) {
  10.       if (candidatePrimes(i)) {
  11.         for (multiple <- i * i to n by i) {
  12.           candidatePrimes -= multiple
  13.         }
  14.       }
  15.     }
  16.  
  17.     candidatePrimes.toSet
  18.   }
  19.  
  20.   def main(args: Array[String]): Unit = {
  21.     val numSquares = args(0).toInt
  22.     val croaks = args(1).map(_ == 'P').toList
  23.     val primeFrog = new PrimeFrog(numSquares)
  24.     println(primeFrog.pSequence(croaks))
  25.   }
  26. }
  27.  
  28. /*
  29.  * This exhaustively calculates the probability of the sequence starting at
  30.  * each square and averages them. The probability of the croak sequence
  31.  * starting at each square is calculated recursively: first calculate the
  32.  * probability of the first croak, then multiply that by the average of the
  33.  * probabilities of the remaining croaks on the two adjacent squares (except on
  34.  * the two ends, then we just take the one adjacent square).
  35.  *
  36.  * Efficiency comes from memoizing results: there will be many checks for the
  37.  * same sequence on the same square.  We store the probability for each
  38.  * trailing subsequence on each square, for a total of N * M map entries, where
  39.  * N is the number of squares and M is the length of the sequence. Since we
  40.  * calculate each of those at most once, runtime is also O(N + M); this assumes
  41.  * that map equality checks on the list of croaks are constant time rather than
  42.  * O(M): using object identity will accomplish this, and is possible given the
  43.  * use of a linked list structure.
  44.  *
  45.  * Ideally, this would be tail recursive or iterative, but I was lazy and at
  46.  * least in the problem statement the sequence is only 15 croaks long, which
  47.  * gives us plenty of stack space.
  48.  *
  49.  * Finally, the problem statement asks for a result in the form of a reduced
  50.  * fraction. I didn't bother doing this, though it would not change the
  51.  * solution dramatically.
  52.  */
  53. class PrimeFrog(numSquares: Int) {
  54.   import PrimeFrog._
  55.   val primeSquares = primesUpTo(numSquares)
  56.   // true => P, false => N
  57.   val pSequenceStartingAtSquareMap = mutable.Map[(List[Boolean], Int), Double]()
  58.  
  59.   def pSequence(seq: List[Boolean]): Double = {
  60.     (1 to numSquares).map(pSequenceStartingAtSquare(seq, _)).sum / (numSquares + 1)
  61.   }
  62.  
  63.   def pSequenceStartingAtSquare(seq: List[Boolean], square: Int): Double = {
  64.     seq match {
  65.       case Nil => 1.0
  66.       case s: ::[Boolean] => {
  67.         pSequenceStartingAtSquareMap.getOrElseUpdate(
  68.           (seq, square),
  69.           calcPSequenceStartingAtSquare(s, square)
  70.         )
  71.       }
  72.     }
  73.   }
  74.  
  75.   def calcPSequenceStartingAtSquare(seq: ::[Boolean], square: Int): Double = {
  76.     val pCurrentCroak = if (seq.head == primeSquares(square)) {
  77.       2.0/3
  78.     } else {
  79.       1.0/3
  80.     }
  81.  
  82.     lazy val pNextSquare = pSequenceStartingAtSquare(seq.tail, square + 1)
  83.     lazy val pPrevSquare = pSequenceStartingAtSquare(seq.tail, square - 1)
  84.  
  85.     val pRemainingCroaks = square match {
  86.       case 0 => pNextSquare
  87.       case s if square == numSquares => pPrevSquare
  88.       case _ => (pNextSquare + pPrevSquare) / 2
  89.     }
  90.  
  91.     pCurrentCroak * pRemainingCroaks
  92.   }
  93. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement