Advertisement
Guest User

Untitled

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