約瑟夫問題:
據說著名猶太曆史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡爲止。
猴子選大王問題:
100 只猴子坐成一個圈,從1開始報數,報到第14的那隻猴子退出圈外,並重新開始計數。依次循環下去,直到圈中只剩下一一隻猴子,就是大王。這個問題其實是一個特例,將其中的100 和14 換成變量n和m,就是約瑟夫環問題。
這是一類相同的問題。
代碼如下:
import java.util.Iterator;
import java.util.LinkedList;
public class Joseph {
public static void main(String[] args){
//創建一個循環鏈表
LinkedList<Integer> linkedList=new LinkedList<>();
int number,cnt; //定義兩個變量,用來計數
int target=10; //報出編號爲target的人退出
//將數的編號放入鏈表中
for(number=1;number<=100;++number){
linkedList.addLast(number);
}
cnt=100;
number=0;
Iterator it=linkedList.iterator();
//循環刪除退出的,知道只剩一個
while (cnt>1){
if(it.hasNext()){
it.next();
number++;
}else {
it=linkedList.iterator(); //到尾部時,將其重新置回到鏈表頭部
}
//刪除符合要求的
if(number==target){
number=0;
it.remove();
cnt--;
}
}
System.out.println("最終編號爲:"+linkedList.element());
}
}
這裏用鏈表(LinkedList)來解決這個問題。將每個人的編號存入到鏈表的一個節點中, 將這些點組成個鏈表。
爲了讓它圍成一個圈,編程的時候需要稍微處理一下,用一個迭代器示每次到達鏈 表尾部的時候,又重新回到鏈表的頭部來。
可以用一個計數器number模擬報數,等於14時,就將指向的節點刪除,表示此人要退出圈外,另外,還要一個計數器cnt記錄已經刪除的節點數,初值爲100,當它爲1時表示已經選出最終數。