Skip to content

Commit a4350ed

Browse files
darkstarstokhos
authored andcommitted
Add solution for Project Euler problem 191 (TheAlgorithms#2875)
* Project Euler problem 191 solution * Add type hints and reference links * Address requested changes - update documentation - split out helper function but mark it with an underscore - remove redundant comments or make them more explicit/helpful * Address requested changes
1 parent 438aaa6 commit a4350ed

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

Diff for: project_euler/problem_191/__init__.py

Whitespace-only changes.

Diff for: project_euler/problem_191/sol1.py

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""
2+
Prize Strings
3+
Problem 191
4+
5+
A particular school offers cash rewards to children with good attendance and
6+
punctuality. If they are absent for three consecutive days or late on more
7+
than one occasion then they forfeit their prize.
8+
9+
During an n-day period a trinary string is formed for each child consisting
10+
of L's (late), O's (on time), and A's (absent).
11+
12+
Although there are eighty-one trinary strings for a 4-day period that can be
13+
formed, exactly forty-three strings would lead to a prize:
14+
15+
OOOO OOOA OOOL OOAO OOAA OOAL OOLO OOLA OAOO OAOA
16+
OAOL OAAO OAAL OALO OALA OLOO OLOA OLAO OLAA AOOO
17+
AOOA AOOL AOAO AOAA AOAL AOLO AOLA AAOO AAOA AAOL
18+
AALO AALA ALOO ALOA ALAO ALAA LOOO LOOA LOAO LOAA
19+
LAOO LAOA LAAO
20+
21+
How many "prize" strings exist over a 30-day period?
22+
23+
References:
24+
- The original Project Euler project page:
25+
https://projecteuler.net/problem=191
26+
"""
27+
28+
29+
cache = {}
30+
31+
32+
def _calculate(days: int, absent: int, late: int) -> int:
33+
"""
34+
A small helper function for the recursion, mainly to have
35+
a clean interface for the solution() function below.
36+
37+
It should get called with the number of days (corresponding
38+
to the desired length of the 'prize strings'), and the
39+
initial values for the number of consecutive absent days and
40+
number of total late days.
41+
42+
>>> _calculate(days=4, absent=0, late=0)
43+
43
44+
>>> _calculate(days=30, absent=2, late=0)
45+
0
46+
>>> _calculate(days=30, absent=1, late=0)
47+
98950096
48+
"""
49+
50+
# if we are absent twice, or late 3 consecutive days,
51+
# no further prize strings are possible
52+
if late == 3 or absent == 2:
53+
return 0
54+
55+
# if we have no days left, and have not failed any other rules,
56+
# we have a prize string
57+
if days == 0:
58+
return 1
59+
60+
# No easy solution, so now we need to do the recursive calculation
61+
62+
# First, check if the combination is already in the cache, and
63+
# if yes, return the stored value from there since we already
64+
# know the number of possible prize strings from this point on
65+
key = (days, absent, late)
66+
if key in cache:
67+
return cache[key]
68+
69+
# now we calculate the three possible ways that can unfold from
70+
# this point on, depending on our attendance today
71+
72+
# 1) if we are late (but not absent), the "absent" counter stays as
73+
# it is, but the "late" counter increases by one
74+
state_late = _calculate(days - 1, absent, late + 1)
75+
76+
# 2) if we are absent, the "absent" counter increases by 1, and the
77+
# "late" counter resets to 0
78+
state_absent = _calculate(days - 1, absent + 1, 0)
79+
80+
# 3) if we are on time, this resets the "late" counter and keeps the
81+
# absent counter
82+
state_ontime = _calculate(days - 1, absent, 0)
83+
84+
prizestrings = state_late + state_absent + state_ontime
85+
86+
cache[key] = prizestrings
87+
return prizestrings
88+
89+
90+
def solution(days: int = 30) -> int:
91+
"""
92+
Returns the number of possible prize strings for a particular number
93+
of days, using a simple recursive function with caching to speed it up.
94+
95+
>>> solution()
96+
1918080160
97+
>>> solution(4)
98+
43
99+
"""
100+
101+
return _calculate(days, absent=0, late=0)
102+
103+
104+
if __name__ == "__main__":
105+
print(solution())

0 commit comments

Comments
 (0)