二战后的某一天,N个日本人来到了一个山洞休息,为了派出一
个日本人去外面充满危险的丛林中采摘食物,他们设置如下游戏产生
外出采摘的人:
1、首先,所有参加游戏的日本人按顺序编号为1、2、3…N;
2、接下来每个日本人心里产生一个数字,这个数字称为序号为 N
的人的密码P;
3、所有参加游戏的人按照编号站成一个圈,长老为游戏设置初
始密码K,从编号为1的人开始报数,报到K的人退出队伍,然后将自
己心中的密码P说出来,由下一个人继续从1开始报数,报到P的人退
出队伍,以此类推;
4、当队伍中剩下一个人的时候,这个人就是今天要出去采摘的
日本人,他可能回不来了!
请各位同学设计程序并使用Java语言实现该程序,在用户输入了
人数N、每个人的密码P和初始密码K的情况下,自动完成上面的选择
过程,输出先后离开队伍的人的序号序列,最后输出要去采摘的日本
人,输出他的编号。如采用图形化形式表示整个游戏过程,本次试验
额外加分。
源码:
import java.util.*;
import javax.swing.*;
public class live {
public static void main(String[] args) {
int N = 0,k = 0;
Scanner in = new Scanner(System.in);
N = Integer.parseInt(JOptionPane.showInputDialog(null, "please input the number of people N:"));
k = Integer.parseInt(JOptionPane.showInputDialog(null, "please input the original password k:"));
//这里定义了三个链表,一个存放所有的密码,一个存放出列的顺序,一个存放人的下标值
LinkedList<Integer> allKeys = new LinkedList<>();
LinkedList<Integer> order = new LinkedList<>();
LinkedList<Integer> indexList = new LinkedList<>();
for(int i = 1;i <= N;i++){
allKeys.add(Integer.parseInt(JOptionPane.showInputDialog(null, "please input the " + i + " key")));
indexList.add(i);
}
// LinkedList<Integer> allKeysCopy = new LinkedList<>(allKeys);//这里没用clone的原因是LinkedList的clone()方法是浅克隆,在之后的remove会存在问题
// System.out.println(allKeysCopy.toString());
// System.out.println(indexList.toString());
int outN;//考虑出队后从出队的人的下一个人开始数,放大outN的作用域
while(N>1){
outN=0;
outN=(k+outN-1)%N;//计算出队的人在链表中的下标
if(outN==0){
outN=N;
}
k = allKeys.get(outN-1);//得到出队人的密码
order.add(indexList.get(outN-1));
indexList.remove(outN-1);
allKeys.remove(outN-1);
N--;
}
// System.out.println(allKeys.toString());
// System.out.println(order.toString());
// System.out.println(indexList.toString());
// System.out.println((indexList.indexOf(allKeys.get(0))+1));
// JOptionPane.showMessageDialog(null,"The last people is num "+(allKeysCopy.indexOf(allKeys.get(0))+1));//LinkedList的下标从0开始
JOptionPane.showMessageDialog(null,"The last people is num "+(indexList.getFirst()));
JOptionPane.showMessageDialog(null,"The dequeue order is "+order.toString());
in.close();
}
}
部分解释:
//这里定义了三个链表,一个存放所有的密码,一个存放出列的顺序,一个存放人的下标值
LinkedList<Integer> order = new LinkedList<>();
LinkedList<Integer> indexList = new LinkedList<>();
//通过求模运算计算出出队人的下标,将下标存储在order表中,得到出对人的密码来进行下一轮的出队。
int outN;//考虑出队后从出队的人的下一个人开始数,放大outN的作用域
while(N>1){
outN=0;
outN=(k+outN-1)%N;//计算出队的人在链表中的下标
if(outN==0){
outN=N;
}
k = allKeys.get(outN-1);//得到出队人的密码
order.add(indexList.get(outN-1));
indexList.remove(outN-1);//在indexList和allKeys中同时删除出队的人,要不然结果会出现重复
allKeys.remove(outN-1);
N--;
}
```
该实验是一个约瑟夫环问题