约瑟夫环是一个很有意思的算法。大意就是:罗马人占领了乔塔帕特,41个人藏在一个山洞中躲过了这场浩劫。这41个人中,包括历史学家约瑟夫(Josephus)和他的一个朋友。剩余的31个人为了表示不想罗马人屈服,决定集体自杀。大家决定了一个自杀方案,所有这41个人围成一个圈,由第1个人开始顺时针报数,每报数为3的人立刻就自杀,然后再由下一个人重新开始报数,仍然是每报数为3的人就立刻自杀,直到所有人都自杀身亡为止。
约瑟夫和他的朋友并不想自杀,于是约瑟夫想到了一个计策,他们两个同样参与到自杀方案中,但是最后却躲过了自杀。
算法思路:
41个人围成一个圈报数,数到3的人就立刻自杀。约瑟夫和朋友想活下来的话,也就是当39个人都数到3并立刻自杀后,约瑟夫和朋友就不遵守自杀的约定,他们就活了下来,也就是他们俩站的初始位置要正确。
现在我们用一个int型数组来存放41个人,数组元素初始值都为0,当第几个数到3的人自杀后,我们用约瑟夫环数标记为几,并记录自杀者的初始位置。当41个人全部自杀后,我们遍历找出倒数前两个自杀的初始位置后,这两个自杀的初始位置就是我们要找的结果。
现在我们用java代码简单实现:
public static final int MaxNum = 41; //约瑟夫环最大成员数
public static final int KillNum = 3; // 数到该数时需要自杀的数字
public static void Josephus(int alive){
int count = 1; //统计自杀的人数,每自杀一个人,则count加1,同时也可用来标记约瑟夫成员位置。
int postion = -1; // 用来定位约瑟夫环成员位置
int i = 0;
//初始化一个数组 数组初始值为0,值为0时为没有自杀。
int []person = new int[MaxNum];
//遍历数组,并标记需要自杀的人
while(count<=MaxNum){
do{
postion = (postion+1)%MaxNum; // 定位约瑟夫环的成员位置
if(person[postion] == 0){ // 筛选没自杀过的成员,自杀过的成员则不进行处理
++i;
}
if(i == KillNum){ // 当没自杀过的成员数到3时,该成员自杀。此刻跳出do while 循环,将自杀者标记
i = 0;
break;
}
}while(true);
person[postion] = count; // count用来统计自杀者的个数,同时也标记为初始位置为(postion+1)自杀者的约瑟夫环环号
System.out.println("位置在"+(postion+1)+"的成员自杀!约瑟夫环号为:"+person[postion]);
count++; // 统计自杀的人数,每自杀一个人,则count加1。
}
System.out.println("---------------------------------------------------------------------------------------------------------");
// 计算想要活下来的人需要站的位置
alive = MaxNum - alive; // 自杀者的最大约瑟夫环数
for(i = 0;i
if(person[i]>alive){ // 活下来的人的约瑟夫环数大于自杀者的最大约瑟夫环数
System.out.println("不想要自杀的人应该站的位置是: "+(i+1)+",约瑟夫环号为:"+person[i]);
}
}
}
public static void main(String []args){
int alive;
Scanner input = new Scanner(System.in);
alive = input.nextInt();
Josephus(alive);
}
}
测试结果:
2
位置在3的成员自杀!约瑟夫环号为:1
位置在6的成员自杀!约瑟夫环号为:2
位置在9的成员自杀!约瑟夫环号为:3
位置在12的成员自杀!约瑟夫环号为:4
位置在15的成员自杀!约瑟夫环号为:5
位置在18的成员自杀!约瑟夫环号为:6
位置在21的成员自杀!约瑟夫环号为:7
位置在24的成员自杀!约瑟夫环号为:8
位置在27的成员自杀!约瑟夫环号为:9
位置在30的成员自杀!约瑟夫环号为:10
位置在33的成员自杀!约瑟夫环号为:11
位置在36的成员自杀!约瑟夫环号为:12
位置在39的成员自杀!约瑟夫环号为:13
位置在1的成员自杀!约瑟夫环号为:14
位置在5的成员自杀!约瑟夫环号为:15
位置在10的成员自杀!约瑟夫环号为:16
位置在14的成员自杀!约瑟夫环号为:17
位置在19的成员自杀!约瑟夫环号为:18
位置在23的成员自杀!约瑟夫环号为:19
位置在28的成员自杀!约瑟夫环号为:20
位置在32的成员自杀!约瑟夫环号为:21
位置在37的成员自杀!约瑟夫环号为:22
位置在41的成员自杀!约瑟夫环号为:23
位置在7的成员自杀!约瑟夫环号为:24
位置在13的成员自杀!约瑟夫环号为:25
位置在20的成员自杀!约瑟夫环号为:26
位置在26的成员自杀!约瑟夫环号为:27
位置在34的成员自杀!约瑟夫环号为:28
位置在40的成员自杀!约瑟夫环号为:29
位置在8的成员自杀!约瑟夫环号为:30
位置在17的成员自杀!约瑟夫环号为:31
位置在29的成员自杀!约瑟夫环号为:32
位置在38的成员自杀!约瑟夫环号为:33
位置在11的成员自杀!约瑟夫环号为:34
位置在25的成员自杀!约瑟夫环号为:35
位置在2的成员自杀!约瑟夫环号为:36
位置在22的成员自杀!约瑟夫环号为:37
位置在4的成员自杀!约瑟夫环号为:38
位置在35的成员自杀!约瑟夫环号为:39
位置在16的成员自杀!约瑟夫环号为:40
位置在31的成员自杀!约瑟夫环号为:41
————————————————————————————————————————
不想要自杀的人应该站的位置是: 16,约瑟夫环号为:40
不想要自杀的人应该站的位置是: 31,约瑟夫环号为:41