1. 程式人生 > >約瑟夫迴圈報數問題

約瑟夫迴圈報數問題

    約瑟夫迴圈問題,根據http://blog.csdn.net/ZCSYLJ/article/details/6830703的文章寫出自己的一些心得體會。

   首先在一個序列中,假如該序列有n個元素,並且以m報數。假設給這個序列進行編號,第一個為0,第二個為1.......則這個序列就是0,1,2,3,........n-1

   那麼第一個出來的人必然是m%n-1。之後便是一個思維的關鍵點,我們把m%n-1之前的數移到最後面並且去除m%n-1這個元素從而組成一個新的序列。

   為什麼要把之前的元素轉移到後面呢?

   因為這是約瑟夫迴圈演算法的一個必須條件,沒有此條件不能完成下面我要說的一個迴圈。不妨假設在這一步中,只剔除m&n-1這個元素。之後繼續進行報數,雖然這樣也是可行的,但是會造成許多的麻煩,原本的2去除,之後需要去除5,之後是8.......並且這樣一來你去掉的那個數字所在的位置要怎麼辦的,是要以0代替?還是什麼別的?由此一來便十分困難,所以當元素轉移之後,每次都是編號為2的元素剔除(不包括最後幾次)。

  之後我們需要對這個序列進行重新編號,原來的編號是:m%n,m%n+1,m%n+2,.......n-1,0,1,2,......m%n-2。

  現在的編號是                                                                   :0,1,2,3,4...........n-2。

  在這裡考慮m%n是考慮到m>n的情況

  之後重複按照先前的兩個步驟迴圈就可以得到最後一個只有一個數字的序列,而這最後一個序列就是你想得到的結果。

  所以這就是一個數學的關於J[n]與J[n-1]之間的關係。並且已經知道了J[0]必然是等於0的。所以現在必須知道J[n]與J[n-1]之間的關係到底是什麼。(J[N]代表最終只剩下一個人該人的編號)

  經過遞迴我們知道了,由於在轉移之前,剔除的數的後一個數現在的編號是0,之前的編號是m%n,所以J[n-1]+m%n=J[n]。考慮到原編號為0之後的情況,需要(J[n-1]+m%n)%n。所以得到了J[n]=(J[n-1]+m%n)%n。這個函式說白了就是一個編號轉換的函式。其實大家如果看不懂這個函式時,往往都以為是這個函式是解出這題的關鍵點,其實不然。愚以為把元素放到後面的這個做法才是最重要的:把一部分元素放到後面,之後重新編號,遞迴。這才是這個約瑟夫迴圈報數的精華思想。

  所以下面就可以附上程式碼了:

#include<iostream>

using namespace std;

int main()

{

int m,n;cin>>m>>n;

int sum=0;

for(int i=2;i<=n;i++)sum=(sum+m%i)%i;

cout<<sum+1;//考慮到實際問題第一個人的編號一般不是0而是1

}