题目
【问题描述】编号为1,2,3,……,n的n个人按顺时针方向围坐在一张圆桌周围。给定一个正整数m<n,从第一个人开始按顺时针方向自1开始报数,每报到m时就让其出列,且计数继续进行下去。如此下去,直到圆桌周围人全部出列为止。最后出列者为优胜者。每个人的出列次序定义了整数1,2,3,……,n的一个排列。这个排列成为一个(n,m)Josephus排列。例如:若(7,3)Josephus排列为3,6,2,7,5,1,4,对于给定的1,2,3,……,n中的K个数,Josephus想知道是否存在一个正整数m(m<n),使得Josephus(n,m)排列最后k个数恰好为事先指定的k个数。
【基本要求】利用单向循环链表存储结构模拟约瑟夫环过程,按照出列顺序输出各人编号。
【测试数据】
输入数据:n = 7,k = 4,指定排列的最后k个数为7、5、1、4。
输出数据:m的值为3。
思路
约瑟夫环:N个人围成一圈报数,报到M个数就出列,并重新从1开始报数。
回忆大二学的数据结构,模拟需用循环链表或循环队列,实现m的情况输出,再截取对比输入的排列判断得到符合的m值。没有输出-1;
循环队列
public static int findM(int n, int k, List<Integer> lk) {
// 约瑟夫环
// 注意:按照出列顺序输出各人编号(队列!!!)
// 找m的值
for (int m = 1; m < n; m++) {
int count = 0;
int index = 0;
List<Integer> res = new LinkedList<>();// 模拟圆桌
LinkedList<Integer> queue = new LinkedList<>();// 出队队列
// 模拟圆桌编号
for (int i = 1; i <= n; i++) {
res.add(i);
}
// 模拟出列过程(全出对比)
while (res.size() !=0) {
count++;
if (count == m) {
count = 0;
queue.addLast(res.get(index));// 入队
res.remove(index);
} else {
index = (index + 1) % res.size();// 循环实现
}
}
System.out.println(queue);
if (queue.subList(n-k,n).equals(lk)) {
return m;
}
}
return -1;
}
循环链表
类似队列,略。
链表类:
class Node {
int data;
Node next;
Node(int data) {
this.data = data;
}
}
循环链表关键实现:
cur.next = head; // 构建循环链表
cur = head;