When is Cheryl’s birthday?

When is Cheryl’s birthday?

推理

第一句话确定:July 14 July 16 August 14 August 15 August 17(告诉B日期不可能为18,19,==>告诉A的月份不可能为May,June)
第二句话确定:July 16 August 15 August 17(日期14有两个,B不可能确定,排除)
第三句话确定:July 16(月份August有两个,A不能确定,推出July16)

###Khanacademy

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env python
# -*- coding: utf-8 -*-
DATES = ['May 15', 'May 16', 'May 19',
'June 17', 'June 18',
'July 14', 'July 16',
'August 14', 'August 15', 'August 17']
def Month(date): return date.split()[0]
def Day(date): return date.split()[1]
#print Month('May 15')
#out:May
#print Day('May 15')
#out:15
def tell(part, possible_dates=DATES):
"Cheryl tells a part of her birthdate to someone; return a new list of possible dates that match the part."
return [date for date in possible_dates if part in date]
def know(possible_dates):
"A person knows the birthdate if they have exactly one possible date."
return len(possible_dates) == 1
#print tell('May')
#out:['May 15', 'May 16', 'May 19']
#print tell('15')
#out:['May 15', 'August 15']
#print know(tell('15'))
#out:False
def cheryls_birthday(possible_dates=DATES):
"Return a list of the possible dates for which statements 3 to 5 are true."
return filter(statements3to5, possible_dates)
def statements3to5(date): return statement3(date) and statement4(date) and statement5(date)
## TO DO: define statement3, statement4, statement5
def statement3(date):
"Albert: I don't know when Cheryl's birthday is, but I know that Bernard does not know too."
possible_dates = tell(Month(date))
return (not know(possible_dates)
and all(not know(tell(Day(d)))
for d in possible_dates))
#print statement3('May 15')
#out:False
#print filter(statement3,DATES)
#out:['July 14', 'July 16', 'August 14', 'August 15', 'August 17']
def statement4(date):
"Bernard: At first I don't know when Cheryl's birthday is, but I know now."
at_first = tell(Day(date))
return (not know(at_first)
and know(filter(statement3, at_first)))
#print filter(statement4,filter(statement3,DATES))
#out:['July 16', 'August 15', 'August 17']
def statement5(date):
"Albert: Then I also know when Cheryl's birthday is."
return know(filter(statement4, tell(Month(date))))
print cheryls_birthday()
#out:['July 16']
print know(cheryls_birthday())
#out:True

Mathematica(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
(*
Procedural answer to the question posted here:
"http://nbviewer.ipython.org/url/norvig.com/ipython/Cheryl.ipynb"
Doing this in other fun mathematica ways is left as an exercise for the reader :)
*)
In[665]:= str = " May 15 May 16 May 19
June 17 June 18
July 14 July 16
August 14 August 15 August 17" ;
dates = Partition[StringSplit[str], 2]
Out[666]= {{"May", "15"}, {"May", "16"}, {"May", "19"}, {"June",
"17"}, {"June", "18"}, {"July", "14"}, {"July", "16"}, {"August",
"14"}, {"August", "15"}, {"August", "17"}}
(* 3. albert didn't know when cheryl's birthday was, but
knew bernard didn't know either. he has revealed that he's holding a
month that does not permit bernard to immediately know. bernard would
only immediately know if the day was unique in the list *)
In[667]:=
monthsWithUniqueDay =
GatherBy[dates, Last] // Select[Length[#] == 1 &] // Catenate //
Map[First]
Out[667]= {"May", "June"}
(* 4. bernard reveals his initial day was ambiguous, it
mapped to multiple months *)
In[668]:=
ambiguousDays =
GatherBy[dates, Last] // Select[Length[#] > 1 &] // Catenate //
Map[Last] // Union;
bernardInitial = dates // Select[MemberQ[ambiguousDays, Last[#] ] &]
Out[669]= {{"May", "15"}, {"May", "16"}, {"June", "17"}, {"July",
"14"}, {"July", "16"}, {"August", "14"}, {"August",
"15"}, {"August", "17"}}
(* 4.3 bernard has incorporated albert's information,
ruling out any months with unique days *)
In[670]:=
bernardNoUniqueDays =
bernardInitial // Select[! MemberQ[monthsWithUniqueDay, First[#]] &]
Out[670]= {{"July", "14"}, {"July", "16"}, {"August",
"14"}, {"August", "15"}, {"August", "17"}}
(* 4.6 bernard says this is good enough to give him the
answer. so what days are potentially unambiguous for him, that are
unique day numbers in the set? *)
In[671]:=
bernardCandidateDays =
Tally[bernardNoUniqueDays[[All, 2]]] // Select[Last[#] == 1 &] //
Map[First]
Out[671]= {"16", "15", "17"}
(* since these are the unique day numbers bernard has, we
know the final answer must be one of these month/day combinations *)
In[672]:=
bernardCandidateAnswers =
Select[bernardNoUniqueDays, MemberQ[bernardCandidateDays, Last@#] &]
Out[672]= {{"July", "16"}, {"August", "15"}, {"August", "17"}}
(* 5. albert says this is good enough to give *him* the answer. which
means albert sees here an unambiguous month. What month is
unambiguous in this set? because that's our answer *)
Select[
GatherBy[bernardCandidateAnswers, First], Length[#] == 1 &]
Out[673]= {{{"July", "16"}}}

Mathematica(2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cand = {{"May", 15}, {"May", 16}, {"May", 19}, {"June", 17}, {"June",
18}, {"July", 14}, {"July", 16}, {"August", 14}, {"August",
15}, {"August", 17}};
c1[n_] :=
With[{rem = Cases[Tally[n[[All, 2]]], {x_, _?(# == 1 &)} :> x]},
DeleteCases[
n, {Alternatives @@ (Cases[n, {_, Alternatives @@ rem}][[All,
1]]), _}]]
c2[n_] :=
With[{rem = Cases[Tally[n[[All, 2]]], {x_, _?(# == 1 &)} :> x]},
Cases[n, {_, Alternatives @@ rem}]]
c3[n_] :=
With[{rem = Cases[Tally[n[[All, 1]]], {x_, _?(# == 1 &)} :> x]},
Cases[n, {Alternatives @@ rem, _}]]
Composition[
Row[{"Cheryl's Birthday is "}~Join~#, Spacer[2]] &, #[[1]] &, c3, c2,
c1][cand]

cand is candidate birthdays
c1 to c3 are the clues from the three statements:(i) rule out months that have unique day (ii) rule out birthdays without unique days (iii) find remaining birthday which has unique month the rest is for “prettiness”

参考