鍊錶應用 Josephus問題

2021-06-22 16:03:12 字數 1678 閱讀 6615

據說著名猶太歷史學家 josephus有過以下的故事:在羅馬人占領喬塔帕特後,39個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也不要被人抓到,於是決定了乙個自殺方式:41個人排成乙個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下乙個重新報數,直到所有人都自殺身亡為止。

然而josephus和他的朋友並不想遵從,josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。

可以用迴圈鍊錶來模擬這個過程,

簡單起見,將人進行編號,自殺的過程看作是數字出列,定義如下結構體:

struct node;

typedef struct node node;

輸入人數(也就是「問題規模」)n和所謂的「自殺數字」(姑且稱它為「間隔」吧)m,按出列順序輸出各數字,直到最後留下的那個數字。

問題的規模n暫且定義在2到10000之間,間隔m定義在1到n之間。其實m大於n也可以,只不過相當於多繞了一圈而已,因此暫定m小於n。

之後就是迴圈鍊錶的生成和節點的刪除了,直到最後只剩1個節點。

在寫**的過程中,個人感覺需要注意以下2個地方:

(1)要檢查輸入是否合理,例如是否是整數,是否符合取值範圍。

(2)由於鍊錶操作過程中,既要用到當前節點,又要用到當前節點的前驅,因此生成鍊錶的初始化函式返回的是尾節點。反正是迴圈鍊錶,首尾相接。這樣一開始的時候,前驅指標就能指向尾節點,當前指標就能指向當前節點。否則,如果生成鍊錶的初始化函式直接返回頭結點,那麼想找到尾節點的話,還要再遍歷一次鍊錶,麻煩了。

整個**如下:

#include #include #define n_max 10000		//人數n的最大取值

struct node;

typedef struct node node;

void solvejosephus(unsigned int, unsigned int);

node * initjosephus(unsigned int);

int main(void)

printf("輸入間隔 m (0 < m < %u):", n);

while(scanf("%u", &m) != 1 || m < 1 || m >= n) //檢查輸入m

solvejosephus(n, m);

return 0;

}//解決josephus問題,列印結果

void solvejosephus(unsigned int n, unsigned int m)

else //該出列了

k++;

} printf("\n最後留下的幸運數字是%d\n", pcurrent->num);

}//建立具有n個節點的單向迴圈鍊錶,n>=2,返回尾指標

node * initjosephus(unsigned int n)

pcurrent->next = head; //首尾相接

return pcurrent;

}

按照故事描述,輸入n=41,m=3,看看結果。

嗯,沒錯。看來josephus果然聰明過人,能在生死關頭做出如此精確計算,佩服!

迴圈鍊錶應用 Josephus

include using namespace std typedef int elemtype struct nodetype void josephus int n,int m,int k p data n p next head p head while p data p next data ...

Josephus問題的鍊錶實現

據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了乙個自殺方式,41個人排成乙個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下乙個重新報數,直到所...

迴圈鍊錶Josephus問題(c,cpp

問題描述 設有n個人圍坐在乙個圓桌周圍,現從第s個人開始報數,數到第m個的人出列,然後從出列的下乙個人重新開始報數,數到第m個的人又出列,如此反覆直到所有的人出列為止。josephus.c 1 include 2 include 3 typedef struct lnode 4lnode,linkl...