約瑟夫問題(有時也稱為約瑟夫斯置換,是一個出現在計算機科學和數學中的問題。在計算機編程的算法中,類似問題又稱為約瑟夫環。又稱“丟手絹問題”.)
基本介紹
- 中文名:約瑟夫問題
- 外文名:Josephus problem
- 別名:約瑟夫斯置換
- 類似問題:約瑟夫環
- 別稱:丟手絹問題
問題來歷
一般形式
pascal代碼1
var a:array [1..20] of integer; n,m,i,j,k,n1,m1:integer;beginreadln(m,n);for i:=1 to m do a[i]:=i;m1:=m;n1:=1;while m1>0 dobegin j:=(n+n1-1-1) mod m1 +1; n1:=j; m1:=m1-1; writeln(a[j]); for k:=j to m1 do a[k]:=a[k+1];end;end.
C++代碼:
#include<iostream>using namespace std;main(){ bool a[101]={0}; int n,m,i,f=0,t=0,s=0; cin>>n>>m; do { ++t;//逐個枚舉圈中的所有位置 if(t>n) t=1;//數組模擬環狀,最後一個與第一個相連 if(!a[t]) s++;//第t個位置上有人則報數 if(s==m)//當前報的數是m { s=0;//計數器清零 cout<<t<<' ';//輸出被殺人編號 a[t]=1;//此處人已死,設定為空 f++;//死亡人數+1 } }while(f!=n);//直到所有人都被殺死為止}
pascal代碼2
var n,m,i,s,p:integer; a:array[1..10000] of integer;begin read(n,m);//這步不用說了吧? for i:=1 to n do a[i]:=1;//先全部賦值1 p:=0;s:=0;//統計人數和報數字用的 repeat for i:=1 to n do begin if a[i]=0 then continue; //用於等會排除出圈者 s:=s+a[i];//不斷累加(報數字) if s=m then//出圈者 begin write(i,' ');列印出圈者; a[i]:=0;//明白剛才continue的意思了吧 p:=p+1;//人數減少一個; s:=0;//重頭報起. end; end; until p=n;//直到人數到了end.
pascal代碼3
Var a:array[1..100] of integer; n,m,i,j,p:integer;Begin write('Input n,m:'); readln(n,m); for i:=1 to n do a[i]:=i; p:=1; {p用於記錄報數的位置} for i:=1 to n do begin j:=0; {j用於記錄報到的人數} while j<m do begin if a[p]<>0 then j:=j+1; if p=n then p:=1 else p:=p+1; {處理邊界情況} end; if p<>1 then begin write(a[p-1],' ');a[p-1]:=0;end {處理邊界情況} else begin write(a[n],' ');a[n]:=0;end; end;end.
pascal代碼4
Var a:array[1..100] of integer; n,m,p,i,j:integer;Begin readln(n,m); for i:=1 to n-1 do a[i]:=i+1; a[n]:=1; p:=n; for i:=1 to n do begin for j:=1 to m-1 do p:=a[p]; write(a[p],' '); a[p]:=a[a[p]]; end;End.
c++
#include <iostream>using namespace std;const int m = 3;int main(){ int n, f = 0; cin >> n; for (int i = 1; i <= n; i++) f = (f + m) % i; cout << f + 1 << endl;}
pascal代碼5
var n,m,i,s:integer;beginwrite('N M =');read(n,m);for i:=2 to n dos:=(s+m) mod i;writeln('The winner is ',s+1);end.
python代碼
#控制參數:nums = 41call = 3#參數定義:peoples = []for _ in range(nums): peoples.append(True)result = []num =1#主邏輯while(any(peoples)): for index,people in enumerate(peoples): if people: if num == call: peoples[index] = False result.append(index+1)# print(index+1)#每輪的出局者 # print(peoples)#每次的佇列狀態 num = 1 else: num += 1print('-'* 25)print('\n總數為%d,報數為%d' % (nums,call)) print('約瑟夫序列為:\n%s\n' % result) print('-'* 25)
約瑟夫問題10e100版(from vijios)
var a,b,c:array[1..105]of longint; la,lb,lc,i:longint; s:string;procedure incc;var i:integer;begin for i:=1 to 105 do c:=c+b; for i:=1 to 104 do if c>9 then begin c:=c+cdiv10; c:=c mod 10; end;end;functioncxiaoa:boolean;vari:integer;begincxiaoa:=false;fori:=105downto1doifc<athenbegincxiaoa:=true;break;endelseifc>athenbreak;end;proceduredoubleb;vari:integer;beginfori:=1to105dob:=b*2;fori:=1to104doifb>9thenbeginb:=b+bdiv10;b:=bmod10;end;end;proceduredecc;vari,j:integer;beginfori:=1to104doifc>=bthenc:=c-belsebeginj:=i+1;whilec[j]=0doinc(j);whilej>idobeginc[j]:=c[j]-1;c[j-1]:=c[j-1]+10;dec(j);end;c:=c-b;end;end;procedurefua;vari:integer;beginfori:=1to104doifa>cthena:=a-celsebegina:=a-1;a:=a+10;a:=a-c;end;end;procedureoutit;vari,j:integer;beginfori:=1to105doa:=a*2;fori:=1to104doifa>9thenbegina:=a+adiv10;a:=amod10;end;ifa[1]>0thena[1]:=a[1]-1elsebeginj:=2;whilea[j]=0doinc(j);whilej>1dobegina[j]:=a[j]-1;a[j-1]:=a[j-1]+10;dec(j);end;a[1]:=a[1]-1;end;fori:=105downto1doifa>0thenbeginj:=i;break;end;fori:=jdownto1dowrite(a);end;beginreadln(s);la:=length(s);fori:=ladownto1doa:=ord(s[la+1-i])-ord('0');b[1]:=1;c[1]:=1;whilecxiaoadobegindoubleb;incc;end;decc;fua;outit;end.
猴子選王
問題表述
編程解決
- 1.C程式
#include <stdio.h>#include <malloc.h>#defineLENsizeof(structmonkey)//定義structmonkey這個類型的長度struct monkey{int num;struct monkey *next;};struct monkey *create(int m){struct monkey *head,*p1,*p2;inti;p1=p2=(struct monkey*)malloc(LEN);head=p1;head->num=1;for(i=1,p1->num=1;i<m;i++){p1=(struct monkey*)malloc(LEN);p1->num=i+1;p2->next=p1;p2=p1;}p2->next=head;return head;}struct monkey *findout(struct monkey *start,int n){int i;struct monkey *p;i=n;p=start;for(i=1;i<n-1;i++)p=p->next;return p;}struct monkey *letout(struct monkey *last){struct monkey *out,*next;out=last->next;last->next=out->next;next=out->next;free(out);return next;}int main(){int m,n,i,king;struct monkey *p1,*p2;printf("請輸入猴子的個數m:\n");scanf("%d",&m);printf("每次數猴子的個數n:\n");scanf("%d",&n);if(n==1){king=m;}else{p1=p2=create(m);for(i=1;i<m;i++){p2=findout(p1,n);p1=p2;p2=letout(p1);p1=p2;}king=p2->num;free(p2);}printf("猴王的編號是:%d\n",king);return 0;}
- C語言程式2
//猴子選大王問題(約瑟夫環問題) #include<stdio.h> #include<string.h> #include<stdlib.h> intfre(charmok[],intk) { inti; printf("\n猴子編號:\n"); for(i=0;mok[i]!='\0';i++) printf("%d\t",mok[i]);//輸出為踢出之前的編號,測試用 for(i=k;mok[i]!='\0';i++) { mok[i]=mok[i+1]; }//一個循環,將k以後的元素前移 putchar('\n'); for(i=0;mok[i]!='\0';i++) printf("%d\t",mok[i]);//輸出踢出之後的編號,測試用 printf("\n按回車繼續下一輪:\n"); getch();//暫停,測試用 return0; } int main() { char mok[50]; int i; int n,s,b;//n表示猴子總數;s表示步進;b表示元素個數及大王編號 int j,k;//j,k都是計數器 mok[0]=1;//初始化mok[0],讓後面編號更簡單的進行 printf("請輸入猴子的總數:\n"); scanf("%d",&n);//輸入猴子的總數 for(i=1;i<n;i++) { mok[i]=i+1; }//對猴子進行編號 mok[n]='\0';//用0來表示數組的結尾 printf("請輸入循環單位:\n"); scanf("%d",&s);//單位長度 b=n;//統計猴子的個數 for(j=1,k=0;;j++,k++) { if(b==1) { b=mok[0]; break; }//如果元素只剩下一個,那么退出循環 if(j==s) { printf("\n它出列了:%d\n",mok[k]); fre(mok,k);//用於元素前移的函式 b--; j=1; }//將猴子從數組中踢出,並重置計數器J。 if(mok[k+1]=='\0') k=-1;//重置計數器k,因為後面有k++所以k要在重置基礎上-1. }//判斷是否為數組最後元素,重置計數器k。 printf("\n最終大王是他:%d\n",b); return0; }
- C語言程式3: 用數組模擬鍊表
#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的下一個人的編號是1node=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);//輸出最後倖存者的編號return 0;}
- pascal程式:
vara:array[1..10000]ofinteger;n,s,i,j:integer;beginread(m,n);fori:=1tomdoa[i]:=1;j:=0;fori:=1tomdobegins:=0;whiles<ndobeginifj<mtheninc(j)elsej:=1;s:=s+a[j];end;write(j);a[j]:=0;end;end.
- c++程式
#include<iostream>#include<conio.h>using namespace std;main(){ int n,m,i,s=0; cout<<"N:";cin>>n; cout<<"M:";cin>>m; for(i=2;i<=n;i++) s=(s+m)%i; cout<<"新的大王是:"<<s+1; getch(); }
- 約瑟夫數學算法
#include<stdio.h>#include<conio.h>intmain(void){intn,i=0,m,p;scanf("%d%d",&n,&m);//n總人數,m步長while(++i<=n){p=i*m;while(p>n)p=p-n+(p-n-1)/(m-1);printf("%d\n",p);}getch();return0;}
- 約瑟夫遞推算法
#include<iostream>usingnamespacestd;intking(intM,intN){intk=0;for(inti=2;i<=M;i++)k=(k+N)%i;return++k;}intmain(){intn,m;while(scanf("%d%d",&n,&m)&&n&&m){cout<<king(n,m)<<endl;}return0;}
- 2、PHP模擬算法
functionking($n,$m){$monkey=range(1,$n);//模擬建立一個連續數組$i=0;while(count($monkey)>1){$i+=1;//開始查數$head=array_shift($monkey);//直接一個一個出列最前面的猴子if($i%$m!=0){array_push($monkey,$head);//如果沒數到m或m的倍數,則把該猴放回尾部去.}//否則就拋棄掉了}return$monkey[0];}echo'剩餘',king(3,4),'號猴子';
def Monkey(n, M): if n == 0 or M == 1: #過濾兩種特殊情況 return 0 L = list(map(list,list(enumerate([True] * n,start=1)))) #兩種狀態以布爾值表示 counter = 0 while [L[i][1] for i in range(len(L))].count(True) > 1: for i in range(len(L)): if L[i][1] == True: counter += 1 if counter % M == 0 and L[i][1] == True: L[i][1] = False return list(filter(lambda x:x[1] == True, L))[0][0] Monkey(2009, 3)