聽說著名猶太曆史學家 Josephus有過如下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,因而決定了一個自殺方式,41我的排成一個圓圈,由第1我的開始報數,每報數到第3人該人就必須自殺,而後再由下一個從新報數,直到全部人都自殺身亡爲止。然而Josephus 和他的朋友並不想聽從。首先從一我的開始,越過k-2我的(由於第一我的已經被越過),並殺掉第k我的。接着,再越過k-1我的,並殺掉第k我的。這個過程沿着圓圈一直進行,直到最終只剩下一我的留下,這我的就能夠繼續活着。問題是,給定了和,一開始要站在什麼地方纔能避免被處決?Josephus要他的朋友先僞裝聽從,他將朋友與本身安排在第16個與第31個位置,因而逃過了這場死亡遊戲。node
這個問題是計算機和數學中經典的一個計數問題,在算法的中這種相似的問題被叫作與瑟夫環。算法
與瑟夫問題有不少的解決思路,好比最多見的使用循環鏈表來解決。數組
#include <stdio.h> #include <stdlib.h> typedef struct node { int data; struct node *next; }node; node *create(int n) { node *p = NULL, *head; head = (node*)malloc(sizeof (node )); p = head; node *s; int i = 1; if( 0 != n ) { while( i <= n ) { s = (node *)malloc(sizeof (node)); s->data = i++; // 爲循環鏈表初始化,第一個結點爲1,第二個結點爲2。 p->next = s; p = s; } s->next = head->next; } free(head); return s->next ; } int main() { int n = 41; int m = 3; int i; node *p = create(n); node *temp; m %= n; // m在這裏是等於2 while (p != p->next ) { for (i = 1; i < m-1; i++) { p = p->next ; } printf("%d->", p->next->data ); temp = p->next ; //刪除第m個節點 p->next = temp->next ; free(temp); p = p->next ; } printf("%d\n", p->data ); return 0; }
我最開始見到這個問題,使用遞歸來解決這個問題。ide
#include<stdio.h> void josephus(int *a,int n, int i) { int times=1; while(number(a,n)>0) { if(i==n+1) { i=1; } while(a[i-1]==0) { i++; if(i==n+1) { i=1; } } if(times==3) { printf("%d->",a[i-1]); a[i-1]=0; i++; josephus(a,n,i); } times++; i++; } } int number(int *a,int n) { int i=0; int times=0; for(i=0;i<n;i++) { if(a[i]==0) { ; } else { times++; } } return times; } int main() { int i; int n=41; int a[n]; for(i=0;i<41;i++) { a[i]=i+1; } josephus(a,n,1); printf("\n"); }
還可使用數組模仿循環鏈表來實現。spa
#include<stdio.h> #include<malloc.h> int main() { int *person,i,node,n,m; scanf("%d%d",&n,&m); person=(int*)malloc(sizeof(int)*(n+1)); for(i=1;i<=n;i++)//初始化圈 { person[i]=i+1;//i表示編號爲i的人,person[i]的值表示編號爲i的人的下一我的的編號 } person[n]=1;//編號爲n的下一我的的編號是1 node=1; while(node!=person[node])//若是某我的的下一我的不是本身,意味着人數超過1人 { for(i=1;i<m-1;i++)//這個循環終止於被殺的人的前一我的 { node=person[node];//下一我的的編號爲node,node的值來自於前一我的的person[node] } printf("%d->",person[node]);//輸出被殺的人編號 person[node]=person[person[node]];//修改被殺的人的前一我的的person[node]爲被殺的人的後一我的的編號 node=person[node];//這句話中的node是被殺的人後一我的 } printf("%d",node);//輸出最後倖存者的編號 printf("\n"); return 0; }