循環鏈表模擬約瑟夫問題

問題來歷:

        據說著名猶太歷史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡爲止。然而Josephus 和他的朋友並不想遵從。首先從一個人開始,越過k-2個人(因爲第一個人已經被越過),並殺掉第k個人。接着,再越過k-1個人,並殺掉第k個人。這個過程沿着圓圈一直進行,直到最終只剩下一個人留下,這個人就可以繼續活着。問題是,給定了和,一開始要站在什麼地方纔能避免被處決?Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。

 解決約瑟夫問題,一般利用數組或者鏈表模擬問題過程,這是比較笨的辦法。但是比較好理解,現在網上也有更便捷的公式了。


創建循環鏈表,模擬遊戲人數,初步代碼

//節點
class Child{
int n0;
Child nextChild;
public Child(int n0)
{
this.n0=n0;
}
}
//循環鏈表
class CycLink{
int len=0;//鏈表長度
Child firstHead=null;
Child temp=null;//跑龍套

public void setLen(int len)
{
this.len=len;
}
//創建鏈表
public void createLink(){
for(int i=1;i<=len;i++)
{
if(i==1){
//創建第一個節點
Child ch=new Child(i);
this.firstHead=ch;
this.temp=ch;
}else{
//最後一個節點
if(i==len){
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
ch.nextChild=this.firstHead;//尾指向頭
}else{
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
}
}
}
}

public void show(){
//先定義一個跑龍套
Child temp=this.firstHead;
do{
System.out.println(temp.n0);
temp=temp.nextChild;
}while(temp!=this.firstHead);
}

}

完整代碼

//節點
class Child{
int n0;
Child nextChild;
public Child(int n0)
{
this.n0=n0;
}
}
//循環鏈表模擬約瑟夫問題
class CycLink{
int len=0;//鏈表長度
Child firstHead=null;
Child temp=null;//跑龍套
int k=0;//開始數數的人
int m=0;//模--數多少下

public void setLen(int len)
{
this.len=len;
}

public void setK(int k)
{
this.k=k;
}

public void setM(int m)
{
this.m=m;
}
//創建鏈表
public void createLink(){
for(int i=1;i<=len;i++)
{
if(i==1){
//創建第一個節點
Child ch=new Child(i);
this.firstHead=ch;
this.temp=ch;
}else{
//最後一個節點
if(i==len){
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
ch.nextChild=this.firstHead;//尾指向頭
}else{
Child ch=new Child(i);
temp.nextChild=ch;
temp=ch;
}
}
}
}

public void play()
{
Child temp=this.firstHead;
Child temp2=null;//爲了刪除節點
//1.先找到開始的人
for(int i=1;i<k;i++)
{
temp2=temp;
temp=temp.nextChild;
}
while(len!=1)
{
//2.數m下
for(int i=1;i<m;i++)
{
temp2=temp;
temp=temp.nextChild;
}
//3.將數到m的刪除
temp2.nextChild=temp.nextChild;//刪除的是temp,將temp前面的temp2的next指向temp的後面(即temp的next)
//如果刪除的是頭結點,怎麼辦
if(temp==this.firstHead)
{
this.firstHead=temp2;
}
temp=temp2.nextChild;
this.len--;
}
System.out.println("遊戲後僅存:"+temp.n0);
}

public void show(){
//先定義一個跑龍套
Child temp=this.firstHead;
do{
System.out.println(temp.n0);
temp=temp.nextChild;
}while(temp!=this.firstHead);
}

}
public class CycLinkTest {//測試是注意類名要修改,與自己設定的類名一致
public static void main(String []args){

CycLink cyclink=new CycLink();
cyclink.setLen(5);
cyclink.createLink();
cyclink.show();
cyclink.setK(1);
cyclink.setM(2);
cyclink.play();
}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章