约瑟夫环问题的描述如下:假设有n个人围成一圈,其编号依次为1, 2, 3, ..., n,现在使这n个人围成一圈,随机抽取一个人并将其剔除;之后依次选取与被剔除人相隔m的人并将其剔除,直到最后剩下一个人。这类问题可以给定最后剩下的人的编号以及n,求解最小的m的值;或者给定n和m,求最后剩下的人的编号。
此类问题解决思路是采用递推法,对于编号为1, 2, 3, ..., n的人,假设我们首先剔除的是编号为k(k = m%n)的人,那么剩下的人的编号为:
1, 2, 3, ... , k-1, k+1, k+2, ..., n-1, n (总共n-1人)
我们将剩下的人的编号做一下映射:
k+1 -----> 1
k+2 -----> 2
k+3 -----> 3
........
n -----> n-k
1 -----> n-k+1
.......
k-1 -----> n-1
由此,我们将问题转化为n-1个人围成一圈,每隔m个人进行剔除,并且编号有如下对应关系:
Josephus(n) = (Josephus(n-1) + k) %n = (Josephus(n-1) + m%n)
因此,约瑟夫环问题可以通过以上递推关系以及Josephus(1) = 0来求解,如ZOJ1088所述问题:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1088
解决该问题的java代码如下所述:
import java.util.Scanner;
public class ZOJ1088 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
while(n != 0){
for(int i = 2; ; i++){
if(Josephus(n-1, i) == 0){
System.out.println(i);
break;
}
}
n = scanner.nextInt();
}
}
public static int Josephus(int n, int i){
if(n == 1)
return 0;
else{
return (Josephus(n-1,i)+i)%n;
}
}
}