一、问题描述。
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
二、代码实现
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
System.out.print("请输入人数:");
int N = in.nextInt(); //定义输入的人数
int a[] = new int[N]; //数组a代表存人的编号
int b[] = new int[N-2]; //数组b用来存取自杀人的编号,比数组a少两位
for(int i = 1; i <= N;i++) { //格式化数组
a[i-1] = i;
}
int k = 0; //记录b数组编号,把a数组自杀的人的编号存到b数组中
int r = 0; //用来数数,数到3的人则自杀
while(b[N-3]==0) { //b数组本来为0,判断最后一个不为零时,,也就是自杀剩余2人时,跳出循环
for(int i = 0;i < N;i++) {
if(a[i]!=0) { //a[i]不为0,则代表该编号的人还存活,数数加1
r++;
}
if(r == 3) {
b[k] = a[i]; //当数到3,该人自杀,把编号存到b数组中
a[i] = 0; //并把a数组该人的编号设为0,代表该人已经自杀
r = 0;
k++;
}
}
}
for(int i = 0; i < N-2;i++) {
System.out.println("自杀的人编号:"+b[i]);
}
for(int i = 0; i < N;i++) {
if(a[i]!=0) {
System.out.println("最后存活的人的编号:"+a[i]);
}
}
}
}
三、运行结果
请输入人数:41
自杀的人编号:3
自杀的人编号:6
自杀的人编号:9
自杀的人编号:12
自杀的人编号:15
自杀的人编号:18
自杀的人编号:21
自杀的人编号:24
自杀的人编号:27
自杀的人编号:30
自杀的人编号:33
自杀的人编号:36
自杀的人编号:39
自杀的人编号:1
自杀的人编号:5
自杀的人编号:10
自杀的人编号:14
自杀的人编号:19
自杀的人编号:23
自杀的人编号:28
自杀的人编号:32
自杀的人编号:37
自杀的人编号:41
自杀的人编号:7
自杀的人编号:13
自杀的人编号:20
自杀的人编号:26
自杀的人编号:34
自杀的人编号:40
自杀的人编号:8
自杀的人编号:17
自杀的人编号:29
自杀的人编号:38
自杀的人编号:11
自杀的人编号:25
自杀的人编号:2
自杀的人编号:22
自杀的人编号:4
自杀的人编号:35
最后存活的人的编号:16
最后存活的人的编号:31