1. 程式人生 > >需找新的美猴王——約瑟夫環 猴王問題

需找新的美猴王——約瑟夫環 猴王問題

猴王問題:
某森林中有n只猴子在商量猴王選舉問題,所有的猴子都想當猴王,
因此大家商量了一個選舉辦法如下:
所有的猴子圍成一圈,先從第一個猴子開始報數,報數到13的猴子就出列。
緊接著的下一個猴子,又從1開始進行新的一輪報數,報數到12的猴子再出列;
依此重複下去,每一輪報數都比上一輪的報數少1,直到報數減為1之後,又從13開始報數。
直到原列中只剩下一個猴子為止,這個猴子就是猴王。

試設計一個程式求出猴王。

約瑟夫環……
很自然地能想到,用連結串列——環形連結串列 比較合適。
建立一個環形的連結串列,每次報數報到的猴子的節點被刪除,C程式實現如下:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 #include "stdafx.h"#include #include /*定義結構型別*/typedefstructMonkey{intid;structMonkey*next;}Monkey;/** * 建立一個有n個節點的環形連結串列 */Monkey*creatList(int
n){Monkey*r=(Monkey*)malloc(sizeof(Monkey));r->id=n;//頭節點儲存連結串列長度r->next=NULL;Monkey*head=r;//記住頭for(inti=1;i<=n;i){Monkey*temp=(Monkey*)malloc(sizeof(Monkey));temp->id=i;temp->next=NULL;r->next=temp;r=r->next;}r->next=head->next;returnhead;//帶頭的連結串列}/** * 誰是眾猴之王? */intlookForTheKing
(Monkey*list){intremainedNum=list->id;Monkey*p=list;//指向頭    /*每次都刪除p->next節點,直至連結串列中除頭只剩一個節點,此時p->next也指向p*/for(intpassword=13;remainedNum>1;password--,remainedNum--){//password = (password > 0 ? password : password  13); //此句可以置換下面的if語句if(!password){password=13;}for(inti=0;i<password-1;i){//因為後面是要刪除p->next,所以p往後移動password-1次p=p->next;}/*刪除p->next節點*/Monkey*temp=p->next;p->next=temp->next;free(temp);}returnp->id;}intmain(intargc,char*argv[]){intn;printf("請輸入猴子的個數n:");scanf("%d",&n);Monkey*list=creatList(n);intking=lookForTheKing(list);printf("/n美猴王是:%d號猴子!//nn",king);return0;}

示例結果:
imageimage
約瑟夫環是一個很經典的問題,最初為——
已知n個人(以編號1,2,3…n分別表示)圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到圓桌周圍的人全部出列。

而變形很多,又比如如下“狐狸抓兔子”問題:

圍繞著山頂有10個洞。一隻兔子和一隻狐狸各住一個洞。 狐狸要吃兔子。
兔子對狐狸說:“你想吃掉我可以,但必須找到我。我就藏身於這十個洞中,
你從10號洞出發,先到1號洞找我,第二次隔一個洞找我,第三次隔兩個洞找我,……,
以後依次類推,若能找到我,可飽餐一頓。”。
狐狸答應了,但是狐狸從早到晚進進出出了1000次,仍沒找到兔子。
請程式設計求兔子究竟躲在哪個洞裡。 

這個問題可以在泛化一點,使山洞的個數和進進出出的次數可變, 同樣用環形連結串列求解,這次不必刪除節點,只需在每個節點(山洞)中加一個標誌變數,標誌其是否被進出過,則C程式碼實現:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 #include "stdafx.h"#include #include using namespacestd;/*為了方便,設為全域性變數*/intnumOfHole;inttimes;/*表示山洞的節點*/typedefstructHole{intid;intisFound;structHole*next;}Hole;/** *建立一個含有numOfHole個節點的連結串列 *id值為 1 - numOfHole */Hole*creatList(){Hole*r=(Hole*)malloc(sizeof(Hole));r->id=0;r->next=NULL;Hole*head=r;//記住頭for(inti=1;i<=numOfHole;i){Hole*temp=(Hole*)malloc(sizeof(Hole));temp->id=i;temp->isFound=0;temp->next=NULL;r->next=temp;r=r->next;}r->next=head->next;returnhead->next;}/** *顯示所有還存在的節點id */voidshowList(Hole*list){if(!list->isFound){printf("%d/t",list->id);}Hole*p=list->next;while(p!=list){if(!p->isFound){printf("%d/t",p->id);}p=p->next;}}/** *找兔子~即執行“進進出出”的動作 */Hole*lookForRabbit(Hole*list){Hole*p=list;p->isFound=1;for(inti=2;i<=times;i){for(intj=0;j<i;j){p=p->next;}p->isFound=1;}returnp;}intmain(intargc,char*argv[]){printf("請輸入洞穴的數量和尋找的次數,用空格隔開: ");scanf("%d%d",&numOfHole,×);Hole*list=creatList();//建立list=lookForRabbit(list);//尋找兔子過程puts("/n兔子可能在的洞穴序號為:");showList(list);//列印所有沒被找過的山洞序號puts("");return0;}

示例結果:
image