一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?
输入格式:
输入在一行中给一个正整数N(≤1000)。
输出格式:
在一行中输出当选猴王的编号。
输入样例:
11
输出样例:
7
问题分析
这个问题实际上是一个经典的约瑟夫环(Josephus Problem)问题。约瑟夫环是一个数学的应用问题:已知n个人(编号从1到n)围成一个圈,从第1个人开始报数,报到m的人出局,剩下的人继续从1开始报数,如此往复,直到只剩下一个人。
在本题中,我们有以下条件:
- n个猴子围成一圈(在样例中n=11)
- 从第1号猴子开始报数
- 每次数到3的猴子被淘汰(即m=3)
- 最后一个留下的猴子成为猴王
我们需要模拟这个过程,找出最后留下的猴子的编号。
解题思路
解决约瑟夫环问题有多种方法:
- 直接模拟法:使用一个数据结构(如链表)来表示圈子,然后模拟报数和删除的过程。
- 递归求解法:使用数学递推公式求解。约瑟夫环问题有一个著名的递推关系:
f(n, m) = (f(n-1, m) + m) % n,其中f(n, m)表示n个人、报数到m时最后剩下的人的编号。
3.循环队列法:使用循环队列模拟报数和删除过程。
在这里,我们将采用直接模拟法,使用LinkedList来表示猴子圈,并模拟整个报数和淘汰的过程
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = 3;
LinkedList<Integer> list = new LinkedList<>();
for (int i = 1; i <= n; i++) {
list.add(i);
}
int cnt = 0, index = 0;
while (!list.isEmpty()) {
cnt++;
index++;
if(index>list.size()) index = 1;
if (cnt == m) {
if(list.size()!=1) {
list.remove(index - 1);
index--;
cnt = 0;
}
else System.out.println(list.removeLast());
}
}
}
}