andrejpodzimek

počet testů [divide et impera]

Mar 26th, 2020
228
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 1.84 KB | None | 0 0
  1. #!/bin/env python3.8
  2.  
  3. import math
  4. import fractions
  5.  
  6. def n_over_k(n, k):
  7.   assert n >= k
  8.   diff = n - k + 1
  9.   gap_start, gap_end = (k + 1, diff) if k < diff else (diff, k + 1)
  10.   return math.prod(range(gap_end, n + 1)) // math.prod(range(2, gap_start))
  11.  
  12. class NumberOfTests:
  13.   def __init__(self, depth, cache=None):
  14.     self.cache = cache or {
  15.       (0, 1) : 1,
  16.       # (1, 1) : fractions.Fraction(5, 2),  # unmixed sample subtree hint
  17.     }
  18.     self.depth = depth
  19.  
  20.   def averageTests(self, infected):
  21.     if not infected:
  22.       return 1
  23.     if (self.depth, infected) in self.cache:
  24.       return self.cache[(self.depth, infected)]
  25.     patients = 2 ** self.depth
  26.     assert infected <= patients
  27.     half_patients = patients // 2
  28.     half_infected = (infected + 1) // 2
  29.     min_infected = max(0, infected - half_patients)
  30.     tests = 0
  31.     weight_sum = 0
  32.     deeper_self = NumberOfTests(self.depth - 1, self.cache)
  33.     for left_infected in range(min_infected, half_infected):
  34.       right_infected = infected - left_infected
  35.       weight = (2 * n_over_k(half_patients, left_infected)
  36.                   * n_over_k(half_patients, right_infected))
  37.       weight_sum += weight
  38.       tests += weight * (
  39.         deeper_self.averageTests(left_infected) +
  40.         deeper_self.averageTests(right_infected))
  41.     if infected % 2 == 0:  # Pascal triangle center
  42.       weight = n_over_k(half_patients, half_infected) ** 2
  43.       weight_sum += weight
  44.       tests += 2 * weight * deeper_self.averageTests(half_infected)
  45.     tests *= fractions.Fraction(1, weight_sum)  # weighted average
  46.     tests += 1  # this vertex
  47.     self.cache[(self.depth, infected)] = tests
  48.     return tests
  49.  
  50. DEPTH = 6
  51. PATIENTS = 2 ** DEPTH
  52.  
  53. nt = NumberOfTests(DEPTH)
  54. for i in range(PATIENTS + 1):
  55.   blah = nt.averageTests(i)
  56.   print(f'{i:02}: {float(blah)} ({str(blah)})')
Add Comment
Please, Sign In to add comment