约瑟夫问题本身好像挺简单,但它的变化形式有很多,各个问题又好像都有一些不一样,实在把人弄得头晕。先看看它的原型。参考百度上这个故事的来源:据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
(多一句嘴,故事被传来传去的,肯定都变了味,依我看这个故事未必完全符合事实。)
我们先简单一些,假设只有10个人,从第一个人开始数数,数到2的那个人就要自杀。
1 2 3 4 5 6 7 8 9 10
8 1 6 2 10 3 7 4 9 5
如上所示,第一排是10个人的序号,第二排则是他们自杀的次序。我们可以看到,第1个人排在第8位自杀,第2个人排在第1位自杀,依此类推。那么这样如果有两个人不想自杀,那么他们可以商量好各自排在第5位和第9位,因为他们是最后两个自杀的,也就是说到了最后就只剩下他们两个了,他们就可以不用自杀了,反正其他人都已经死了,没人知道他们俩作弊。
参考代码:http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/JosephusProblem.htm
public class Josephus {
public static void main(String[] args) {
Josephus j=new Josephus();
int[] man=j.jos(10, 2);
for(int e:man) System.out.print(e+"<<");
System.out.println();
for(int i=0;i<10;i++){
if(man[i]>=9){
System.out.println("作弊的人可以排在第 "+(i+1)+" 位");
}
}
}
public int[] jos(int number,int per){
int man[]=new int[number];
int pos=-1;
for(int count=1;count<=number;count++){
int i=0;
while(i<per){
pos=(pos+1)%number;
if(man[pos]==0)
i++;
}
man[pos]=count;
}
return man;
}
}
结果:
8<<1<<6<<2<<10<<3<<7<<4<<9<<5<<
作弊的人可以排在第 5 位
作弊的人可以排在第 9 位
把那两句改成约瑟夫的处境:
int[] man=j.jos(41, 3);
for(int i=0;i<41;i++){
if(man[i]>=40){
System.out.println("作弊的人可以排在第 "+(i+1)+" 位");
}
}
运行结果:
作弊的人可以排在第 16 位
作弊的人可以排在第 31 位