約瑟夫問題,也是被稱爲丟手絹問題。利用C++或者Java的單向環形鏈表能夠較好的解決,但肯定不是最簡單的方法。就僅僅是我在學習Java的過程中的一個小的作業題。
問題的來源,據說著名猶太歷史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡爲止。然而Josephus 和他的朋友並不想遵從。首先從一個人開始,越過k-2個人(因爲第一個人已經被越過),並殺掉第k個人。接着,再越過k-1個人,並殺掉第k個人。這個過程沿着圓圈一直進行,直到最終只剩下一個人留下,這個人就可以繼續活着。問題是,一開始要站在什麼地方纔能避免被處決?Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。
具體的要求參見度娘:約瑟夫問題
/**
* 作者:迷了路的鹿
* 功能:約瑟夫問題(丟手帕問題)
* 時間:2018年9月14日 09:17:01
*/
public class Demo4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
CycLink cyclink = new CycLink();
int len=41;
int k=1;
int m=3;
cyclink.setLen(len);
cyclink.creatLink();
cyclink.show();
cyclink.setK(k);
cyclink.setM(m);
cyclink.playgame();
}
}
class Node
{
int no;
Node nextNode = null;
//節點的構造函數
public Node(int no)
{
//給一個編號
this.no = no;
}
}
//環形鏈表
class CycLink
{
//先定義一個指向鏈表第一個節點的引用
//指向第一個節點的引用不能動
Node firstNode = null;//沒有新開闢空間,它在紙上談兵!!!!
Node tempNode =null;//跑龍套的選手!!!很重要!!!!(紙上談兵)
int len = 0;//表示共有多少個節點(Node)
int k =0;//表示要從第k個節點開始計數
int m =0;//表示每數到m個節點要被刪除
//設置鏈表的大小(長度)
public void setLen(int len)
{
this.len = len;
}
//設置從第k個人開始計數
public void setK(int k)
{
this.k=k;
}
//設置從第m個人開始計數
public void setM(int m)
{
this.m=m;
}
//初始化環形鏈表
public void creatLink()
{
for(int i=1;i<= len ;i++)
{
if(i==1)
{
//創建第一個節點
Node ch=new Node(i);//ch可不是紙上談兵,實實在在的開闢了空間
this.firstNode = ch;//“紙上”的firstNode指向了有實際空間的ch
this.tempNode = ch;//“紙上”的tempNode指向了有實際空間的ch
}
else //其餘節點(不是第一個頭結點)
{
if(i==len)//(如果要創建最後一個節點)
{
//創建最後一個節點
Node ch=new Node(i);//創建(實際開闢)最後節點,以第二個爲例
tempNode.nextNode = ch;//"紙上"的tempNode.nextNode指向2節點
tempNode = ch;//在“紙上”變更龍套選手
tempNode.nextNode = this.firstNode;//純粹紙上談兵,龍套(最後節點)的下個節點指回初始節點
}
else
{
//繼續創建一個節點
Node ch=new Node(i);//創建(實際開闢)下一個節點,以第二個爲例
tempNode.nextNode = ch;//"紙上"的tempNode.nextNode指向2節點
tempNode = ch;//在“紙上”變更龍套選手
}
}
}
}
//開始丟手帕遊戲
public void playgame()
{
//1、找到第k個節點
Node temp1=null;
Node temp2=null;
temp1 = firstNode;
for(int i=1; i<k; i++)
{
temp1=temp1.nextNode;
}
int cn=1;//刪除的順序標誌
while(len!=1)
{
//2、從第1步中找到的k人開始計數,找第m-1個用戶(方便第3步修改其下個節點的指向)
for(int j=1; j<m-1; j++)
{
temp1=temp1.nextNode;
}
//3、將第2步中找到的用戶修改其下個節點的指向
temp2=temp1.nextNode;//temp2就是要被刪去的節點
System.out.println("第"+cn+"個刪除的節點編號:"+ temp2.no);
temp1.nextNode=temp2.nextNode;
temp1 = temp1.nextNode;
cn++;
len--;
}
//4、顯示最後剩下的節點
System.out.println("最後剩下的節點是:"+temp1.no);
}
//打印該循環鏈表
public void show()
{
//定義個龍套選手
Node temp=this.firstNode;//將“龍套”選手的“帽子”扣在第一個節點上
System.out.print("初始節點編號: ");
do {
System.out.print(temp.no+" ");
temp = temp.nextNode;
}while(temp!=this.firstNode);
System.out.println(" ");
}
}