This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,10 @@
[[wp:Josephus problem|Josephus problem]] is a math puzzle with a grim description: <math>n</math> prisoners are standing on a circle, sequentially numbered from <math>0</math> to <math>n-1</math>. An executioner walks along the circle, starting from prisoner <math>0</math>, removing every <math>k</math>-th prisoner and killing him. As the process goes on, the circle becomes smaller and smaller, until only one prisoner remains, who is then freed. For example, if there are <math>n=5</math> prisoners and <math>k=2</math>, the order the prisoners are killed in (let's call it the "killing sequence") will be 1, 3, 0, and 4, and the survivor will be #2.
'''Task''' Given any <math>n, k > 0</math>, find out which prisoner will be the final survivor. In one such incident, there were 41 prisoners and every 3rd prisoner was being killed (<math>k=3</math>). Among them was a clever chap name Josephus who worked out the problem, stood at the surviving position, and lived on to tell the tale. Which number was he?
'''Extra''' The captors may be especially kind and let <math>m</math> survivors free, and Josephus might just have <math>m-1</math> friends to save. Provide a way to calculate which prisoner is at any given position on the killing sequence.
'''Notes'''
# You can always play the executioner and follow the procedure exactly as described, walking around the circle, counting (and cutting off) heads along the way. This would yield the complete killing sequence and answer the above questions, with a complexity of probably <math>O(kn)</math>. However, individually it takes no more than <math>O(m)</math> to find out which prisoner is the <math>m</math>-th to die.
# If it's more convenient, you can number prisoners from <math>1</math> to <math>n</math> instead. If you choose to do so, please state it clearly.
# An alternative description has the people committing assisted suicide instead of being executed, and the last person simply walks away. These details are not relevant, at least not mathematically.

View file

@ -0,0 +1,2 @@
---
note: Puzzles

View file

@ -0,0 +1,43 @@
with Ada.Command_Line, Ada.Text_IO;
procedure Josephus is
function Arg(Idx, Default: Positive) return Positive is -- read Argument(Idx)
(if Ada.Command_Line.Argument_Count >= Index
then Positive'Value(Ada.Command_Line.Argument(Index)) else Default);
Prisoners: constant Positive := Arg(Idx => 1, Default => 41);
Steps: constant Positive := Arg(Idx => 2, Default => 3);
Survivors: constant Positive := Arg(Idx => 3, Default => 1);
Print: Boolean := (Arg(Idx => 4, Default => 1) = 1);
subtype Index_Type is Natural range 0 .. Prisoners-1;
Next: array(Index_Type) of Index_Type;
X: Index_Type := (Steps-2) mod Prisoners;
begin
Ada.Text_IO.Put_Line
("N =" & Positive'Image(Prisoners) & ", K =" & Positive'Image(Steps) &
(if Survivors > 1 then ", #survivors =" & Positive'Image(Survivors)
else ""));
for Idx in Next'Range loop -- initialize Next
Next(Idx) := (Idx+1) mod Prisoners;
end loop;
if Print then
Ada.Text_IO.Put("Executed: ");
end if;
for Execution in reverse 1 .. Prisoners loop
if Execution = Survivors then
Ada.Text_IO.New_Line;
Ada.Text_IO.Put("Surviving: ");
Print := True;
end if;
if Print then
Ada.Text_IO.Put(Positive'Image(Next(X)));
end if;
Next(X) := Next(Next(X)); -- "delete" a prisoner
for Prisoner in 1 .. Steps-1 loop
X := Next(X);
end loop;
end loop;
end Josephus;

View file

@ -0,0 +1,24 @@
; Since AutoHotkey is 1-based, we're numbering prisoners 1-41.
nPrisoners := 41
kth := 3
; Build a list, purposefully ending with a separator
Loop % nPrisoners
list .= A_Index . "|"
; iterate and remove from list
i := 1
Loop
{
; Step by 2; the third step was done by removing the previous prisoner
i += kth - 1
if (i > nPrisoners)
i := Mod(i, nPrisoners)
; Remove from list
end := InStr(list, "|", 0, 1, i)
bgn := InStr(list, "|", 0, 1, i-1)
list := SubStr(list, 1, bgn) . SubStr(list, end+1)
nPrisoners--
}
Until (nPrisoners = 1)
MsgBox % RegExReplace(list, "\|") ; remove the final separator

View file

@ -0,0 +1,20 @@
nPrisoners := 41
kth := 3
list := []
; Build a list of 41 items
Loop % nPrisoners
list.insert(A_Index)
; iterate and remove from list
i := 1
Loop
{
; Step by 3
i += kth - 1
if (i > list.MaxIndex())
i := Mod(i, list.MaxIndex())
list.remove(i)
}
Until (list.MaxIndex() = 1)
MsgBox % list.1 ; there is only 1 element left

View file

@ -0,0 +1,46 @@
#include <stdio.h>
// m-th on the reversed kill list; m = 0 is final survivor
int jos(int n, int k, int m) {
int a;
for (a = m + 1; a <= n; a++)
m = (m + k) % a;
return m;
}
typedef unsigned long long xint;
// same as jos(), useful if n is large and k is not
xint jos_large(xint n, xint k, xint m) {
if (k <= 1) return n - m - 1;
xint a = m;
while (a < n) {
xint q = (a - m + k - 2) / (k - 1);
if (a + q > n) q = n - a;
else if (!q) q = 1;
m = (m + q * k) % (a += q);
}
return m;
}
int main(void) {
xint n, k, i;
n = 41;
k = 3;
printf("n = %llu, k = %llu, final survivor: %d\n", n, k, jos(n, k, 0));
n = 9876543210987654321ULL;
k = 12031;
printf("n = %llu, k = %llu, three survivors:", n, k);
for (i = 3; i--; )
printf(" %llu", jos_large(n, k, i));
putchar('\n');
return 0;
}

View file

@ -0,0 +1,4 @@
(defun kill (n k &aux (m 0))
(loop for a from (1+ m) upto n do
(setf m (mod (+ m k) a)))
m)

View file

@ -0,0 +1,22 @@
(defun make-circular-list (n)
(let* ((list (loop for i below n
collect i))
(last (last list)))
(setf (cdr last) list)
list))
(defun kill (n d)
(let ((list (make-circular-list n)))
(flet ((one-element-clist-p (list)
(eq list (cdr list)))
(move-forward ()
(loop repeat (1- d)
until (eq list (cdr list))
do (setf list (cdr list))))
(kill-item ()
(setf (car list) (cadr list)
(cdr list) (cddr list))))
(loop until (one-element-clist-p list) do
(move-forward)
(kill-item))
(first list))))

View file

@ -0,0 +1,27 @@
import std.stdio, std.algorithm, std.array, std.string, std.range;
T pop(T)(ref T[] items, in size_t i) pure {
auto aux = items[i];
items.remove(i);
items.length--;
return aux;
}
string josephus(in int n, in int k) {
auto p = iota(n).array();
int i;
int[] seq;
while (!p.empty) {
i = (i + k - 1) % p.length;
seq ~= p.pop(i);
}
return xformat("Prisoner killing order: %(%d, %).\nSurvivor: %d",
seq[0 .. $-1], seq[$ - 1]);
}
void main() {
writeln(josephus(5, 2));
writeln();
writeln(josephus(41, 3));
}

View file

@ -0,0 +1,49 @@
package main
import "fmt"
// basic task function
func finalSurvivor(n, k int) int {
// argument validation omitted
circle := make([]int, n)
for i := range circle {
circle[i] = i
}
k--
exPos := 0
for len(circle) > 1 {
exPos = (exPos + k) % len(circle)
circle = append(circle[:exPos], circle[exPos+1:]...)
}
return circle[0]
}
// extra
func position(n, k, pos int) int {
// argument validation omitted
circle := make([]int, n)
for i := range circle {
circle[i] = i
}
k--
exPos := 0
for len(circle) > 1 {
exPos = (exPos + k) % len(circle)
if pos == 0 {
return circle[exPos]
}
pos--
circle = append(circle[:exPos], circle[exPos+1:]...)
}
return circle[0]
}
func main() {
// show basic task function on given test case
fmt.Println(finalSurvivor(41, 3))
// show extra function on all positions of given test case
fmt.Println("Position Prisoner")
for i := 0; i < 41; i++ {
fmt.Printf("%5d%10d\n", i, position(41, 3, i))
}
}

View file

@ -0,0 +1,40 @@
import java.util.ArrayList;
public class Josephus {
public static int execute(int n, int k){
int killIdx = 0;
ArrayList<Integer> prisoners = new ArrayList<Integer>(n);
for(int i = 0;i < n;i++){
prisoners.add(i);
}
System.out.println("Prisoners executed in order:");
while(prisoners.size() > 1){
killIdx = (killIdx + k - 1) % prisoners.size();
System.out.print(prisoners.get(killIdx) + " ");
prisoners.remove(killIdx);
}
System.out.println();
return prisoners.get(0);
}
public static ArrayList<Integer> executeAllButM(int n, int k, int m){
int killIdx = 0;
ArrayList<Integer> prisoners = new ArrayList<Integer>(n);
for(int i = 0;i < n;i++){
prisoners.add(i);
}
System.out.println("Prisoners executed in order:");
while(prisoners.size() > m){
killIdx = (killIdx + k - 1) % prisoners.size();
System.out.print(prisoners.get(killIdx) + " ");
prisoners.remove(killIdx);
}
System.out.println();
return prisoners;
}
public static void main(String[] args){
System.out.println("Survivor: " + execute(41, 3));
System.out.println("Survivors: " + executeAllButM(41, 3, 3));
}
}

View file

@ -0,0 +1,2 @@
survivor[n_, k_] := Nest[Most[RotateLeft[#, k]] &, Range[0, n - 1], n - 1]
survivor[41, 3]

View file

@ -0,0 +1,8 @@
my @prisoner = 0 .. 40;
my $k = 3;
until (@prisoner == 1) {
push @prisoner, shift @prisoner for 1 .. $k-1;
shift @prisoner;
}
print "Prisoner @prisoner survived.\n"

View file

@ -0,0 +1,14 @@
>>> def j(n, k):
p, i, seq = list(range(n)), 0, []
while p:
i = (i+k-1) % len(p)
seq.append(p.pop(i))
return 'Prisoner killing order: %s.\nSurvivor: %i' % (', '.join(str(i) for i in seq[:-1]), seq[-1])
>>> print(j(5, 2))
Prisoner killing order: 1, 3, 0, 4.
Survivor: 2
>>> print(j(41, 3))
Prisoner killing order: 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 0, 4, 9, 13, 18, 22, 27, 31, 36, 40, 6, 12, 19, 25, 33, 39, 7, 16, 28, 37, 10, 24, 1, 21, 3, 34, 15.
Survivor: 30
>>>

View file

@ -0,0 +1,30 @@
/* REXX **************************************************************
* 15.11.2012 Walter Pachl - my own solution
* 16.11.2012 Walter Pachl generalized n prisoners + w killing distance
* and s=number of survivors
**********************************************************************/
dead.=0 /* nobody's dead yet */
n=41 /* number of alive prisoners */
nn=n /* wrap around boundary */
w=3 /* killing count */
s=1 /* nuber of survivors */
p=-1 /* start here */
killed='' /* output of killings */
Do until n=s /* until one alive prisoner */
found=0 /* start looking */
Do Until found=w /* until we have the third */
p=p+1 /* next position */
If p=nn Then p=0 /* wrap around */
If dead.p=0 Then /* a prisoner who is alive */
found=found+1 /* increment found count */
End
dead.p=1
n=n-1 /* shoot the one on this pos. */
killed=killed p /* add to output */
End /* End of main loop */
Say 'killed:'subword(killed,1,20) /* output killing sequence */
Say ' 'subword(killed,21) /* output killing sequence */
Say 'Survivor(s):' /* show */
Do i=0 To 40 /* look for the surviving p's */
If dead.i=0 Then Say i /* found one */
End

View file

@ -0,0 +1,25 @@
/*REXX pgm, Josephus problem: N men standing in a circle, every Kth kilt*/
parse arg N K Z R . /*get optional arguments. */
if N==',' | N=='' then N = 41 /*no #prisoners? Then use default*/
if K==',' | K=='' then K = 3 /*no kill count? " " " */
if Z==',' | Z=='' then Z = 0 /*no initial # ? " " " */
if R==',' | R=='' then R = 1 /*no remaining#? " " " */
$=; x=; do pop=Z for N; $=$ pop; end /*populate the prisoner's circle.*/
c=0 /*initial prisoner count-off num.*/
do remove=0; p=words($) /*keep removing until R are left.*/
c=c+K /*bump prisoner count-off by K.*/
if c>p then do /* [↓] remove some prisoner(s).*/
do j=1 for words(x); $=delword($,word(x,j)+1-j,1)
if words($)==R then leave remove /*slaying done yet?*/
end /*j*/
c=(c//p)//words($); x= /*adjust prisoner count-off &list*/
end
if c\==0 then x=x c /*list of prisoners to be removed*/
end /*remove*/ /*remove 'til R prisoners left.*/
say 'removing every ' th(K) " prisoner out of " N ' (starting at' Z") with ",
R ' survivor's(R)"," ; say 'leaving prisoner's(R)':' $
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────subroutines──────────────────────────*/
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1)
th: arg y; return y||word('th st nd rd', 1+y//10*(y//100%10\==1)*(y//10<4))

View file

@ -0,0 +1,13 @@
def main
n = (ARGV[0] || 41).to_i
k = (ARGV[1] || 3).to_i
puts josephus(n,k)
end
def josephus(n, k)
prisoners = (0...n).to_a
prisoners.rotate!(k-1).shift while prisoners.length > 1
return prisoners.first
end
main

View file

@ -0,0 +1,27 @@
def executed( prisonerCount:Int, step:Int ) = {
val prisoners = ((0 until prisonerCount) map (_.toString)).toList
def behead( dead:Seq[String], alive:Seq[String] )(countOff:Int) : (Seq[String], Seq[String]) = {
val group = if( alive.size < countOff ) countOff - alive.size else countOff
(dead ++ alive.take(group).drop(group-1), alive.drop(group) ++ alive.take(group-1))
}
def beheadN( dead:Seq[String], alive:Seq[String] ) : (Seq[String], Seq[String]) =
behead(dead,alive)(step)
def execute( t:(Seq[String], Seq[String]) ) : (Seq[String], Seq[String]) = t._2 match {
case x :: Nil => (t._1, Seq(x))
case x :: xs => execute(beheadN(t._1,t._2))
}
execute((List(),prisoners))
}
val (dead,alive) = executed(41,3)
println( "Prisoners executed in order:" )
print( dead.mkString(" ") )
println( "\n\nJosephus is prisoner " + alive(0) )

View file

@ -0,0 +1,14 @@
proc josephus {number step {survivors 1}} {
for {set i 0} {$i<$number} {incr i} {lappend l $i}
for {set i 1} {[llength $l]} {incr i} {
# If the element is to be killed, append to the kill sequence
if {$i%$step == 0} {
lappend killseq [lindex $l 0]
set l [lrange $l 1 end]
} else {
# Roll the list
set l [concat [lrange $l 1 end] [list [lindex $l 0]]]
}
}
return [lrange $killseq end-[expr {$survivors-1}] end]
}

View file

@ -0,0 +1,2 @@
puts "remaining: [josephus 41 3]"
puts "remaining 4: [join [josephus 41 3 4] ,]"