题目
HDU1443——约瑟夫问题
时间限制:2000ms;空间限制:65536KB。
问题描述:约瑟夫问题是众所周知的。有n个人,编号为 1,2,⋯,n站在一个圆圈中,每隔m 个人就杀一个人,最后仅剩下一个人。约瑟夫很聪明,可以选择最后一个人的位置,从而挽救他的生命。例如,当n=6 且m=5时,按顺序出列的人员是 5,4,6,2,3,1,那么1会活下来。
假设在圈子里前面怡好有 k 个好人,后面恰好有 k 个坏人,则必须确定所有坏人都在第一个好人前面被杀的最小m。
输入格式:输入文件中包含若干行,每行一个k,最后一行为 0,可以假设0<k<14。
输出格式:输出文件中每行给出输人文件中的 k 对应的最小m。
输人样例:
3
4
0
输出样例:
5
30
思路
- m 表示隔几个人杀人,因为需要坏人全部先被杀,所以 m 从 k+1 开始递增
- leave 表示存活下来的人数,最开始有 2 * k 个人,直到小于 k 时退出循环(如果leave 小于 k 就说明有好人被杀了,所以leave 不能小于 k)
- p 代表一个指针,最开始指向第一个人(下标是 0),要隔 m 个人杀一个人就让 (p+m-1)%leave(取模是为了防止越界), p 表示要杀的人的下标
- 如果发现这个下标 p 小于 k,就说明杀的是好人,就退出内层循环,让m++
- 如果发现 leave(存活下来的人数)等于 k,就说明坏人全部被杀了,留下来的都是好人,就把 m 返回
代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
int k = sc.nextInt();
if (k == 0) {
break;
}
System.out.println(Joseph(k));
}
}
public static int Joseph(int k) {
int leave, p;
for (int m = k + 1; ; m++) {
for (leave = 2 * k, p = 0; k < leave; leave--) {
p = (p + m - 1) % leave;
if (p < k) {
leave = 0;
}
}
if (leave == k) {
return m;
}
}
}
}