1、引言
与前面我们介绍的大多数程序问题一样,约瑟夫环问题也是来自于一个故事。
这个故事发生在一个名叫约瑟夫的犹太人身上,据说在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人 开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
但是,但是,哈哈,这个时候人性的自私就出现了,约瑟夫和他的朋友都不想死,怎么办呢?这个时候,约瑟夫想到了一个问题,这样一直循环下来,肯定是有3个人坚持到最后的,那么只要保证自己和朋友在最后三个人中就行了,还要保证最后一个需要自杀的是另外的一个人?如何保证呢?经过计算,约瑟夫发现,如果自己和朋友分别站在第16个位置和第31个位置,就会避免自杀的命运。
但是,你知道这是怎么计算出来的么?今天,我们就让程序帮我们解决这个问题。
2、描述
通用型的约瑟夫环问题的描述是:由N个人围成一个圈,从K个人开始报数,到M值出圈,然后再从1开始报数,到M出圈,一直到所有人都出圈。
基于上面的描述,我们大概可以整理出约瑟夫环游戏的整体思路如下:
2.1 一群人围在一起坐成环状(如:N)
2.2 从某个编号开始报数(如:K)
2.3 数到某个数(如:M)的时候,此人出列,下一个人重新报数
2.4 一直循环,直到所有人出列,约瑟夫环结束
3、代码
在描述中,我们已经清晰了解到了整个程序的执行流程,已经类似于伪代码,这里我们直接写出代码,不再写伪代码了,大家见谅。
public class Josephus {
public static int[] arrayOfJosephus(
int number, int per) {
int[] man = new int[number];
for(int count = 1, i = 0, pos = -1;
count <= number; count++) {
do {
pos = (pos+1) % number; // 环状处理
if(man[pos] == 0)
i++;
if(i == per) { // 报数为3了
i = 0;
break;
}
} while(true);
man[pos] = count;
}
return man;
}
public static void main(String[] args) {
int[] man = Josephus.arrayOfJosephus(41, 3);
int alive = 3;
System.out.println("约琴夫排列:");
for(int i = 0; i < 41; i++)
System.out.print(man[i] + " ");
System.out.println("\nL表示3个存活的人要放的位置:");
for(int i = 0; i < 41; i++) {
if(man[i] > alive)
System.out.print("D");
else
System.out.print("L");
if((i+1) % 5 == 0)
System.out.print(" ");
}
System.out.println();
}
}
4、总结
在众多的编程问题中,很多都来自于数学游戏,而数学是计算机科学的基础工程。大家如果想学习一些常用的算法,可以去找找这样类似的书籍看看,自己亲自动手敲一下,相信会有很大的提高。
数学使人周密,祝大家学习愉快。