法一:定义一个猴子个数大小的数组,其值均为1,代表初始时猴子都在圈中,随着报数的进行,报数为3的猴子对应的数组值为0,再进行新一轮报数,最终,当只有一个数组值为1时,结束循环,其为猴子大王。
import java.util.Scanner;
import java.lang.Math;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main (String [] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int [] index = new int[N];
for (int i = 0; i < N; i++) {
index[i] = 1;
}
int n = N; //圈子中剩余的猴子数目
int b = 0; //报数
while (n > 1) {
for (int j = 0; j < N; j++) {
b += index[j];
if (b == 3) {
index[j] = 0;
n--;
b = 0;
}
}
}
for (int k = 0; k < N; k++) {
if (index[k] != 0) {
System.out.println(k+1);
}
}
}
}
法二:约瑟夫问题,也是每次剔除一个报数为m的猴子(需要剔除n次),有递推公式,p(x) = (x + m ) % i;x是倒数第i轮循环中猴王的索引,i是该轮循环所包含的猴子总数,p(x)是倒数第i-1轮循环中猴王的索引下标,最后一轮循环,剩下一个猴王,其索引为0,即i=1,x=0
参考文章:https://blog.csdn.net/u011954296/article/details/51351982
import java.util.Scanner;
import java.lang.Math;
public class Main {
public static void main (String [] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int result = 0;//猴王最后一轮循环的索引
//从倒数第二轮循环开始,倒数第n轮也就是初始状态
for (int i = 2; i <= n; i++) {
result = (result + 3) % i;
}
System.out.print(result + 1);
}
}
法三:用数组来模拟循环链表进行,last代表检测指针test上一次所在的位置,便于之后更新节点找对位置(因为删除节点之后,链表中间会有跳跃,只用一个test来进行的话,只能找到test-1的节点,中间有跳跃的话会使得代码报错)。数组中的值代表本只猴子的下一只猴子索引,当本只猴子的下一只猴子是自己时,循环结束,找到了猴子王。
import java.util.Scanner;
import java.lang.Math;
public class Main {
public static void main (String [] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = 1;//用于计数(相当于报数)
int [] node = new int [n];
for (int i = 0; i < n -1; i++) {
node[i] = i + 1;
}
int test = 0;
int last;
while (test != node[test]) {
last = test;
test = node[test];
k++;
if (k == 3) {
node[last] = node[test]; //模拟删除节点,也就是记录删除节点的下一个节点的索引
k = 0;//此时该节点已经报数为3,为了下一个节点报数为1,应该重置为0
}
}
System.out.println(test + 1);
}
}
贴个自己画的图,怕之后忘记了!节点左边是自己的索引,右边是下一只猴子的索引。