/* * This is a fixed version of a FlySwatter program. It performs well on the Server VM. * * The only difference between this program and the slow program is that * in the slow program FlySwatter object extends Application and the object contents is executed, * whereas this version explicitly defines "main" method in the FlySwatter object. * */ import java.io._ object FlySwatter { case class Square(x1: Double, y1: Double, side: Double) { val x2 = x1 + side val y2 = y1 + side def area = side*side def isValid = side > 0 def contractBy(f: Double): Square = { if (2*f >= side) { Square(x1 + side/2, y1 + side/2, 0) } else { Square(x1 + f, y1 + f, side - 2*f) } } } case class Case(f: Double, rr: Double, t: Double, r: Double, g: Double) def parseData: Seq[Case] = { val in = new BufferedReader(new InputStreamReader(System.in)) def readCase: Case = { def readWords: Seq[String] = in.readLine.split(' ').filter(_.length > 0) val caseData = readWords.map(_.toDouble) Case(caseData(0), caseData(1), caseData(2), caseData(3), caseData(4)) } val numCases = in.readLine.toInt val cases = for (i <- (1 to numCases).force) yield readCase cases } def calculateProbability(c: Case): Double = { def pointInCircle(x: Double, y: Double, r: Double): Boolean = { x*x + y*y < r*r } def squareAndCircleIntersectionArea(s: Square, r: Double): Double = { // calculates the definite integral from a to b of sqrt(r^2-x^2) dx def integrateCirclePart(a: Double, b: Double, r: Double): Double = { def i(x: Double): Double = x*Math.sqrt(r*r - x*x)/2 + r*r/2 * Math.asin(x/r) i(b)-i(a) } assert(s.x1 > 0 && s.y1 > 0) assert(r > 0) if (s.isValid) { val lowerLeftInCircle = pointInCircle(s.x1, s.y1, r) // using lazy vals for these four booleans val upperLeftInCircle = pointInCircle(s.x1, s.y2, r) // makes the program run ~25% slower, val lowerRightInCircle = pointInCircle(s.x2, s.y1, r) // however real performance hit is probably lower val upperRightInCircle = pointInCircle(s.x2, s.y2, r) // because the measurement precision is quite low val area: Double = (lowerLeftInCircle, upperLeftInCircle, lowerRightInCircle, upperRightInCircle) match { case (false, _, _, _) => 0 // square is outside of the circle case (true, _, _, true) => s.area // whole square is in the circle case (true, false, false, false) => // single corner is in the circle val x = Math.sqrt(r*r - s.y1*s.y1) integrateCirclePart(s.x1, x, r) - (x-s.x1)*s.y1 case (true, true, false, _) => // left side of the square is in the circle integrateCirclePart(s.y1, s.y2, r) - (s.y2-s.y1)*s.x1 case (true, false, true, _) => // bottom side of the square is in the circle integrateCirclePart(s.x1, s.x2, r) - (s.x2-s.x1)*s.y1 case (true, true, true, false) => // 3 corners of the square are in the circle val x = Math.sqrt(r*r - s.y2*s.y2) (x-s.x1)*(s.y2-s.y1) + integrateCirclePart(x, s.x2, r) - (s.x2-x)*s.y1 } assume(area >= 0) area } else { 0 // empty square } } assert(c.g + 2*c.r > 0) val maxI = Math.ceil((c.rr - c.t - c.r)/(c.g + 2*c.r)).toInt val squares = for { i <- 0 until maxI; j <- 0 until maxI // until method creates a lazy list, thus we get a lazy list of Squares in the end x1 = c.r + i*(c.g + 2*c.r) y1 = c.r + j*(c.g + 2*c.r) } yield Square(x1, y1, c.g).contractBy(c.f) val squaresAndCircleIntersectionArea = (0.0 /: squares.map(squareAndCircleIntersectionArea(_, c.rr - c.t - c.f)))((a: Double, b: Double) => a+b) val flyIsSafeProb = squaresAndCircleIntersectionArea / (Math.Pi * c.rr * c.rr / 4) 1-flyIsSafeProb } def main(args: Array[String]): Unit = { val cases = parseData for (i <- 0 until cases.length) { val prob = calculateProbability(cases(i)) System.out.printf("Case #%1$d: %2$.6f\n", Array[Object](new java.lang.Integer(i+1), new java.lang.Double(prob))) } } }