day04
题目:如何利用约瑟夫环来保护你和你的朋友?
题目描述:
传说著名犹太学家Josephus有过以下的故事:在罗马人占领桥塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞里,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人拍成了一个圆圈,从第一个人开始数数,每数到第3个人该人就必须自杀,然后再由下一个人开始重新报数,直到所有人都自杀身亡为止。
虽然Josephus和他的朋友并不愿遵从,但是Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个和第31个位置,于是逃过了这场死亡游戏。
约瑟夫问题可用代数分析来求解,假设现在你与m个朋友不行参与了这个游戏,你要如何保护你和你的朋友?
解析:
实际上只要画两个圆圈就可以让自己与朋友免于死亡游戏,这两个圆圈中内圈是排列顺序,而外圈是自杀顺序,如图所示:
如果要使用公式来求解,那么只要将阵列当作环状来处理,在阵列中由计数1开始,每三个数得到一个计数,直到计数为41为止,然后将阵列由索引1开始列出,就可以得知每个位置的自杀顺序,这就是约瑟夫排列,41人报数的约瑟夫排列如下所示:
14 36 1 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23
由上可知,最后一个自杀人是在第31个位置,而倒数第二个自杀的人要排在第16个位置,之前的人都死了,所以他们也就不知道约瑟夫与他的朋友有没有遵守游戏规则,是在代码为:
<script>
var N=41,M=3,man=[],count=1,i=0,pos=-1,
alive=3;//想救的人数
while(count<=N){
do{
pos=(pos+1)%N;//环状处理
if(!man[pos])
i++;
if(i==M){//报数为3
i=0;
break;
}
}while(1);
man[pos]=count;
count++;
}
console.log('约瑟夫排列:',man.join(''));
var txt='L表示要救的'+alive+'个人要放的位置:';
for(i=0;i<N;i++){
if(man[i]>(N-alive))
txt+='L';
else
txt+='D';
if((i+1)%5==0)
txt+=' ';
}
console.log(txt);
</script>