約瑟夫(Josephus)問題

2021-07-15 06:09:15 字數 1472 閱讀 3185

一群小孩圍成一圈,任意假定乙個數n,從第乙個小孩起,順時針方向數,每數到第m個小孩時,該小孩便離開。小孩不斷離開,圈子不斷縮小。最後剩下的乙個小孩便是勝者。求勝者的編號?

/************************************     

// 函式名稱: josephus

// 作 成 者:erick.wang

// 作成日期:2016/07/19

// 返 回 值: void

// 參 數: m,n

// 函式說明:用於解決約瑟夫問題

1.對於1……n的資料,宣告乙個2n的陣列;

2.定義兩個指標cur和tail,分別用於標記當前訪問的資料和最後乙個資料;

3.每訪問過乙個都將其放置到陣列最後位置,當cur的訪問次數是m的倍數時,

將該位置的資料標記為剔除狀態;

4.當tail指標滿的時候將剩餘數字前移,繼續第3步操作。

//************************************/

#define m 2

#define n 8

int a[n*2 + 1];

void josephus(int m,int n)

while (1)

printf("\n");

if (step == m)

if (count == n-1)

a[tail + 1] = a[cur];

//a[cur] = 0;

cur ++;

tail ++;

step ++;

if (tail == n*2+1)

}return;

}

以上方法雖然能解決問題,但是當n和m在成百上千的時候時間消耗也是很大的,所以對此問題先用數學模型進行分析,然後再求解,以下有個更快速的方法,時間複雜度為o(n)。

令f表示i個人玩遊戲報m退出最後勝利者的編號,最後的結果自然是f[n]

遞推公式

f[1]=0;

f[i]=(f[i-1]+m) mod i; (i>1)

有了這個公式,我們要做的就是從1-n順序算出f的數值,最後結果是f[n]。因為實際生活中編號總是從1開始,我們輸出f[n]+1

由於是逐級遞推,不需要儲存每個f,程式如下:

#include 

using

namespace

std;

const

int m = 3;

int main()

for (int i = 1; i <= n; i++)

f = (f + m) % i;

cout

<< f + 1

<< endl;

return

0;}

參考的資料:

很精彩:

Josephus 約瑟夫 問題

問題描述 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為1的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到剩下最後乙個人。程式的意圖是求出最後留下的人的編號。c 實現 include include include u...

josephus(約瑟夫)問題

author zhangchao time 2011年3月31日17 24 11 from c語言競賽題目大全第三題 include include 有 n 個小孩圍成一圈,給他們從1 開始依次編號,現指定從第 w個開始報數,報到第s 個時,該小 孩出列,然後從下乙個小孩開始報數,仍是報到 s 個出...

Josephus問題(約瑟夫環)

描述 有n個人坐在一圈做遊戲,給他們編號為1到n,現從1號人開始傳遞乙份烤肉,傳遞m次停下,將拿著烤肉的人從圈中退出,圈縮小,將烤肉給退出的人後面的人,然後開始繼續傳遞m次停下,又將拿著烤肉的人從圈中退出,圈縮小,依次類推,直到剩下乙個人,那個人就可以品嚐烤肉了,作程式,看看最後的獲勝者是誰?分析 ...