The problem is named after Flavius Josephus, a Jewish historian living in the 1st century. According to Josephus’ account of the siege of Yodfat, he and his 40 soldiers were trapped in a cave by Roman soldiers. They chose suicide over capture, and settled on a serial method of committing suicide by drawing lots. Josephus states that by luck or possibly by the hand of God, he and another man remained until the end and surrendered to the Romans rather than killing themselves. This is the story given in Book 3, Chapter 8, part 7 of Josephus’ The Jewish War.
People are standing in a circle waiting to be executed. Counting begins at a specified point in the circle and proceeds around the circle in a specified direction. After a specified number of people are skipped, the next person is executed. The procedure is repeated with the remaining people, starting with the next person, going in the same direction and skipping the same number of people, until only one person remains, and is freed.
For our solution:
- The point where the executions begin will be at 12 o’clock if we distribute all the people evenly over a circle.
- The direction is clockwise
- The number of skips is 0, meaning person 1 kills the person immediately to their left.
Let’s try with 9 people.
n = 9;
k(n) = 3;
because, given
1,2,3,4,5,6,7,8,9
1 kills 2
3 kills 4
5 kills 6
7 kills 8
Remaining are:
1,3,5,7,9
we now start at 9 because 1 is next to 9 if the numbers are arranged in a circle.
9 kills 1
3 kills 5
Remaining are:
9,3,7
We now start at 7
7 kills 9
Remaining are:
3, 7
3 kills 7
The winner is number 3
Let’s write some code to do this for us.
See the Pen The Josephus Problem by Amando Abreu (@amando96) on CodePen.
Feel free to change the input and even feel free to change the code, I’ve included a simple test case.
This is a list of the input n(number of people) and output k(n)(which number survives) from 1 to 100.
n | k(n) |
---|---|
1 | 1 |
2 | 1 |
3 | 3 |
4 | 1 |
5 | 3 |
6 | 5 |
7 | 7 |
8 | 1 |
9 | 3 |
10 | 5 |
11 | 7 |
12 | 9 |
13 | 11 |
14 | 13 |
15 | 15 |
16 | 1 |
17 | 3 |
18 | 5 |
19 | 7 |
20 | 9 |
21 | 11 |
22 | 13 |
23 | 15 |
24 | 17 |
25 | 19 |
26 | 21 |
27 | 23 |
28 | 25 |
29 | 27 |
30 | 29 |
31 | 31 |
32 | 1 |
33 | 3 |
34 | 5 |
35 | 7 |
36 | 9 |
37 | 11 |
38 | 13 |
39 | 15 |
40 | 17 |
41 | 19 |
42 | 21 |
43 | 23 |
44 | 25 |
45 | 27 |
46 | 29 |
47 | 31 |
48 | 33 |
49 | 35 |
50 | 37 |
51 | 39 |
52 | 41 |
53 | 43 |
54 | 45 |
55 | 47 |
56 | 49 |
57 | 51 |
58 | 53 |
59 | 55 |
60 | 57 |
61 | 59 |
62 | 61 |
63 | 63 |
64 | 1 |
65 | 3 |
66 | 5 |
67 | 7 |
68 | 9 |
69 | 11 |
70 | 13 |
71 | 15 |
72 | 17 |
73 | 19 |
74 | 21 |
75 | 23 |
76 | 25 |
77 | 27 |
78 | 29 |
79 | 31 |
80 | 33 |
81 | 35 |
82 | 37 |
83 | 39 |
84 | 41 |
85 | 43 |
86 | 45 |
87 | 47 |
88 | 49 |
89 | 51 |
90 | 53 |
91 | 55 |
92 | 57 |
93 | 59 |
94 | 61 |
95 | 63 |
96 | 65 |
97 | 67 |
98 | 69 |
99 | 71 |
100 | 73 |
You can see some patterns start to emerge, and it seems like 1 appears at specific intervals.
k(n) = 1 shows up at n = 1,2,4,8,16,32,64.
If you know binary, you know what these numbers mean. They can be expressed as such:
1 = 20; 2 = 21; 4 = 22; 8 = 23; 16 = 24; 16 = 25; 32 = 26; 64 = 27.
128 is out of bounds for this data set, but if we run the function with n = 128(28), we should get k(128) = 1.
After changing the input of our function, we indeed got k(128) = 1, why is that? Does it repeat forever?
Let’s try the first 100 2a. But wait, these numbers get very big very fast. Javascript can handle a maximum array size of 232-1 according to the ECMA-262 5th Edition specification due to being bound by an unsigned 32-bit integer due to the ToUint32 abstract operation, so the closest power of two we can try is 231. But my browser crashes.
The biggest I can do in a few seconds is 215 = 32768. And it’s true, it’s equal to 1.
So we can say that
if n = 2a
then k(n) = 1.
When doing this exercise manually it was less obvious, but the way I built the code made it more obvious as to why.
In JavaScript, array keys start at 0. For everyone to kill the person to their left starting with person 1, is the same as filtering out/eliminating every person in a key whose modulo is equal to 0.
…. to be continued