1. 程式人生 > >約瑟夫環問題(二):(難度:2顆星)

約瑟夫環問題(二):(難度:2顆星)

問題描述:

編號為1,2,…,n的n個人按順時針方向圍坐一圈,任選一個正整數作為報數上限m,從第一個人開始按順時針方向從自1開始順序報數,報道m時停止報數.報m的人出列,從他的順時針方向上的下一個人開始重新從1報數,如此下去,直至所有人全部出列為止,輸出最後一個出列的人的編號。

輸入輸出描述:

m和n由使用者輸入,並且保證m和n的範圍是【1,10000000】,輸出最後出列的編號。

問題分析:

為了方便說明,我們稍微轉換一下,假定標號是0到n-1,報數從0到m-1(主要是因為m%n是可能等於0的,這樣的轉換方便後面的運算),反正最後的結果加1就可以了。

假定當前序列的人數是n,則第一個出列的人的編號是(m-1) % n,下一次報數的人的編號為m%n,令k=m%n,我們重新對剩下的n-1個人進行組織,可以得到如下對應關係:

k->0
k+1->1
k+2->2
k+3->3
k+4->4
……..
k-4->n-4
k-3->n-3
k-2->n-2
k-1->n-1

這個過程實際就是n個人的約瑟夫環問題降為了n-1個人的約瑟夫環問題,用同樣的方法,我們可以得到n-2個人的約瑟夫環問題,一直到1個人的約瑟夫環問題,從這個不斷縮小規模的過程中,我們可以發現編號的對應關係,如果在n-1個人的情況下某個人的編號是x,那麼這個人在n個人的情況下的編號一定是(x+k)%n

同理,如果我們求出t個人玩的時候最後出局的人標號為f(t),那麼t+1個人玩的時候出局的編號就是(f(t) + k)%(t+1)

最後結果總結成一個遞推關係是為:
f(n)=(f(n-1)+k)%n=(f(n-1)+m%n)%n=(f(n-1)+m)%n

PS:

如果是要求出這個約瑟夫環的出隊序列,可以參考我的另外一篇文章:

http://blog.csdn.net/yi_ming_he/article/details/72859577

參考程式碼:

#include <stdio.h>

int main()
{
    int ans = 0, i, n, m;
    scanf_s("%d%d", &n, &m);
    for (i = 1; i <= n; i++)
        ans = (ans + m
) % i; //因為開始是從0開始的,還原原來的問題所以加1 printf("%d\n", ans + 1); return 0; }

執行結果:

這裡寫圖片描述