約瑟夫環:遞歸算法
假設下標從0開始,0,1,2 .. m-1共m個人,從1開始報數,報到k則此人從環出退出,問最后剩下的一個人的編號是多少?
現在假設m=10
0 1 2 3 4 5 6 7 8 9 k=3
第一個人出列后的序列為:
0 1 3 4 5 6 7 8 9
即:
3 4 5 6 7 8 9 0 1(*)
我們把該式轉化為:
0 1 2 3 4 5 6 7 8 (**)
則你會發現: ((**)+3)%10則轉化為(*)式了
也就是說,我們求出9個人中第9次出環的編號,最后進行上面的轉換就能得到10個人第10次出環的編號了
設f(m,k,i)為m個人的環,報數為k,第i個人出環的編號,則f(10,3,10)是我們要的結果
當i=1時, f(m,k,i) = (m+k-1)%m
當i!=1時, f(m,k,i)= ( f(m-1,k,i-1)+k )%m
所以程序如下:
int fun(int m,int k,int i){ if(i==1) return (m+k-1)%m; else return (fun(m-1,k,i-1)+k)%m; } int main(int argc, char* argv[]) { for(int i=1;i<=10;i++) printf("第%2d次出環:%2d\n",i,fun(10,3,i)); return 0; }
第 1次出環: 2 第 2次出環: 5 第 3次出環: 8 第 4次出環: 1 第 5次出環: 6 第 6次出環: 0 第 7次出環: 7 第 8次出環: 4 第 9次出環: 9 第10次出環: 3
數學解(提供思路):
參考C#做法(據說不是很好)
常用算法(C#): 約瑟夫環問題 約瑟夫環問題: 設有n個人圍坐在圓桌周圍,現從某個位置m(1≤m≤n)上的人開始報數,報數到k的人就站出來。 繼續下一個人,即原來的第k+1個位置上的人,又從1開始報數,再報數到k的人站出來。依此重復下去,直到全部的人都站出來為止 using System; using System.Collections.Generic; using System.Text; namespace ExJose { class ClassJose { //從第start人開始計數,以alter為單位循環記數出列,總人數為total public int[] Jose(int total, int start,int alter) { int j, k = 0; //count數組存儲按出列順序的數據,以當結果返回 int[] count = new int[total + 1]; //s數組存儲初始數據 int[] s = new int[total + 1]; //對數組s賦初值,第一個人序號為0,第二人為1,依此下去 for (int i = 0; i < total; i++) { s[i] = i; } //按出列次序依次存於數組count中 for (int i = total; i >= 2; i--) { start = (start + alter - 1) % i; if (start == 0) start = i; count[k] = s[start]; k++; for (j = start + 1; j <= i; j++) s[j - 1] = s[j]; } count[k] = s[1]; //結果返回 return count; } static void Main(string[] args) { ClassJose e=new ClassJose (); int[] a = e.Jose(10,3,4); for (int i = 0; i < a.Length; i++) { Console.WriteLine(a[i].ToString ()); } } } }