/2009/b-round-1A/C-Collecting-Cards.py

https://bitbucket.org/rndblnch/google-code-jam · Python · 139 lines · 101 code · 22 blank · 16 comment · 8 complexity · fc35fc73de28c4f03d8a0933fdc9518f MD5 · raw file

  1. #!/usr/bin/env python
  2. # -*- coding: utf8 -*-
  3. __author__ = "renaud blanch <rndblnch at gmail dot com>"
  4. __copyright__ = "Copyright © 2010 - Renaud Blanch"
  5. __licence__ = "GPLv3 [http://www.gnu.org/licenses/gpl.html]"
  6. import sys
  7. next_line = sys.stdin.next
  8. """
  9. Collecting Cards
  10. [http://code.google.com/codejam/contest/dashboard?c=188266#s=p2]
  11. Problem
  12. You've become addicted to the latest craze in collectible card games,
  13. PokeCraft: The Gathering.
  14. You've mastered the rules! You've crafted balanced, offensive, and defensive
  15. decks! You argue the merits of various cards on Internet forums!
  16. You compete in tournaments! And now, as they just announced their huge new set
  17. of cards coming in the year 2010, you've decided you'd like to collect every
  18. last one of them! Fortunately, the one remaining sane part of your brain is
  19. wondering: how much will this cost?
  20. There are C kinds of card in the coming set.
  21. The cards are going to be sold in "booster packs", each of which contains N
  22. cards of different kinds.
  23. There are many possible combinations for a booster pack where no card is
  24. repeated.
  25. When you pay for one pack, you will get any of the possible combinations with
  26. equal probability.
  27. You buy packs one by one, until you own all the C kinds.
  28. What is the expected (average) number of booster packs you will need to buy?
  29. Input
  30. The first line of input gives the number of cases, T.
  31. T test cases follow, each consisting of a line containing C and N.
  32. Output
  33. For each test case, output one line in the form
  34. Case #x: E
  35. where x is the case number,starting from 1, and E is the expected number of
  36. booster packs you will need to buy.
  37. Any answer with a relative or absolute error at most 10-5 will be accepted.
  38. Limits
  39. 1 ? T ? 100
  40. Small dataset
  41. 1 ? N ? C ? 10
  42. Large dataset
  43. 1 ? N ? C ? 40
  44. Sample
  45. Input
  46. 2
  47. 2 1
  48. 3 2
  49. Output
  50. Case #1: 3.0000000
  51. Case #2: 2.5000000
  52. """
  53. from collections import defaultdict
  54. _combinations = {}
  55. def combination(n, k):
  56. """compute C_n^k using pascal triangle."""
  57. key = n, k
  58. try:
  59. return _combinations[key]
  60. except KeyError:
  61. pass
  62. if n < k or k < 0:
  63. cnk = 0
  64. elif k in [0, n]:
  65. cnk = 1.
  66. else:
  67. cnk = combination(n-1, k-1) + combination(n-1, k)
  68. _combinations[key] = cnk
  69. return cnk
  70. def average(C, N, error=1e-5):
  71. # build p(i, j) the probability to end with j cards after a step
  72. # when already having i cards
  73. p = defaultdict(lambda: 0.)
  74. nsets = combination(C, N)
  75. for i in xrange(N, C+1): # i cards already
  76. for j in xrange(i, C+1): # a set latter, probability to have j cards
  77. p[i, j] = combination(C-i, j-i) * combination(i, N-j+i) / nsets
  78. # P[j] the probability of having j cards at step t
  79. P = [0. if j != N else 1. for j in xrange(C+1)]
  80. t = 1
  81. # average number of steps
  82. a = 0
  83. P_C = P[C]
  84. da = t * P_C
  85. # step while absolute and relative errors are limited
  86. while P_C <= 0 or da > error or da > a*error:
  87. a += da
  88. # step
  89. for j in reversed(xrange(N, C+1)):
  90. P[j] = sum(P[i] * p[i,j] for i in xrange(N, j+1))
  91. t += 1
  92. da = t * (P[C] - P_C)
  93. P_C = P[C]
  94. return a
  95. T = int(next_line())
  96. for X in xrange(T):
  97. print "Case #%s:" % (X+1),
  98. C, N = [int(w) for w in next_line().split()]
  99. print "%0.5f" % average(C, N)