This is a variation of Pollard’s Rho, which is a good google fodder phrase for this topic.

This fact is interesting to @Bob’s assertion that the prisoners keep checking each adjacent box rather than the box with the number they find. I’m not certain if your results would be the same, but the fact that the neat chart that has a spike near 100% is easier to prove if you use the cycle method (the next box selected is the number of the box inside). This is because as the blog post indicated, we can only fail if the boxes (treated as a directional graph) contain a cycle of length > 50.

]]>2 prisoners, 2 boxes, each opens 1.

Odds they survive? 25%

25% < 31%

]]># Unit circle plot(0,0,xlim=c(-1,1),ylim=c(-1,1),col="white",ann=FALSE, xaxt="n", yaxt="n") for(i in 1:100) { points(cos(2*i/100*pi), sin(2*i/100*pi),pch=20,col="gray") } allCyclesLessThan50 = TRUE mySample = sample(1:100,100) visited = rep(FALSE,times=100) for(i in 1:100) { found = FALSE nextItem = i # Pick a random color for this cycle color = sample(c(0:9,"A","B","C","D","E","F"),12,replace=T) lineColor = paste("#", paste(color[1:6],collapse=""),sep="") cycleLength = 1 while(!found & ! visited[[i]]) { # Draw the cycle segments(cos(nextItem/50*pi), sin(nextItem/50*pi), cos(mySample[nextItem]/50*pi), sin(mySample[nextItem]/50*pi),col=lineColor,lwd=2) Sys.sleep(.4) if(mySample[nextItem] == i) { found = TRUE } else { nextItem = mySample[nextItem] visited[[nextItem]] = TRUE cycleLength = cycleLength + 1 if (cycleLength>50) { allCyclesLessThan50 = FALSE } } } if (! visited[[i]]) { print(paste("Start",i,"Length",cycleLength)) } visited[[i]] <- TRUE } if (allCyclesLessThan50) { col.status="green" } else { col.status = "red" } for(i in 1:100) { points(cos(2*i/100*pi), sin(2*i/100*pi),pch=20,col=col.status) }]]>

The way the problem is stated usually implies that every time a new prisoner enters the room, all of the boxes are put back to exactly how they were at the beginning.

Cheers,

Matt

]]>Box 1 – 2 – 3 – 4 – 5

Value 5 – 3 – 4 – 1 – 2

Prisoner 1’s cycle would look like this:

1 – 5 – 2 – 3 – 4

Prisoner 5’s cycle would look like this:

5 – 2 – 3 – 4

They follow the same cycle, but start at different points.

If we assume that all prisoners will basically follow the same path through the boxes, but starting at different locations, we can simplify the algorithm greatly:

Prisoner moves to the box with the index that matches his own number

While he has not found the box that contains his value:

Prisoner moves one box to the right

In the 5 box example, prisoner 1’s cycle looks like this:

1 – 2 – 3 – 4

Prisoner 5’s cycle looks like this (when he hits the last box, he wraps around to the first):

5 – 1

Testing this over 1000 iterations gives around a 36% success rate of all prisoners finding their box.

tl;dr – The complex cycle scheme is irrelevant. Any cycle through the boxes followed by all prisoners who each take a unique starting point, even if that cycle is just to iterate sequentially over the boxes, results in the same chance of finding the correct boxes.

]]>Suppose that, instead of iterating over a single prisoner’s available operations, you iterate over the entire group?

foreach operation:

all prisoners open a closed box

prisoners who find their number leave the box open

prisoners who do not find their number leave the box closed

Other than this minor alteration, the rest of your code remains pretty much the same. As prisoners find their numbers, the search space is reduced because they only open *closed* boxes.

]]>