猴子選大王 約瑟夫問題

2021-09-11 20:13:13 字數 3328 閱讀 7468

例題描述

由m只猴子圍成一圈,從1到m進行編號,打算從中選出乙個大王,經過協商,決定選出大王的規則:從第乙個開始迴圈報數,

數到n的猴子出圈,下乙個猴子從1開始報數。

輸入樣例

3 2【輸出樣例

3方法一:

//模擬法

#include

using namespace std;

#define max 100

long a[max+1];

long m,n,i,count,k;

intmain()

a[k]=0

;//猴子k出圈

} cout

}

分析:上程式發現:當猴子出圈後,程式也會一一檢查是否出圈,在這裡花了大量的時間。

方法二:利用陣列存放下乙個該報數的編號,以8只猴子為例,a[1]的值為2,意思是指2號猴子,

如下所示

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

a[8]23

4567

81這樣構成了乙個環,如果5號猴子出圈就用語句a[4]=a[a[4]],以後報到4號猴子時,就直接指向6號猴子。

#include

using namespace std;

#define n 100000

long a[max+1]

long m,n,i,count,k;

intmain()

cout

}

為了更好的理解我列出來第一次小迴圈後的陣列值:

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

a[8]33

4567

81所以每次點名到1的時候回跳過二號值,外迴圈進行到m次時要出去的k值即為大王的位置。

方法三:

倒退演算法:如果我們知道這個子問題的答案:設x是猴王,那麼根據對應關係就有以下的對應關係,f[i]=(f[i-1]+k)%i;(k為每次需要喊的次數)

//倒退演算法

#include

using namespacestd;

intmain()

例題描述】變形約瑟夫問題

給出k與n,求k%i(1<=i<=n),即求出k%1+k%2+k%3+k+…+k%n的值。

輸入格式

兩個整數k與n(k>=1,n<109)。

輸出格式

乙個正整數ans=k%i+

樣例輸入

10 10

樣例輸出

13方法一:

#include

//變形約瑟夫問題解法一

using namespace std;

intmain()

但由於k和n資料規模過大(k>=1,n<109),所以我們要進行優化。由於題目中沒有指明k與n的大小比較,所以可能的情況有以下三種:

(1) 1i12

3456

78910

1112

1314

1516

k%i001

0142

0765

4321

0可以發現當i>k/2時,k%i的值為等差數列。

因此,我們可以將前半部分劃分為前後兩部分。

後面部分是乙個公差為1的等差數列,即(k/2)

-1,(k/2)-2,…4,3,2,1,0,直接使用等差數列求和公式算出即[k%2-1]+[k%2-2]+[k%2-3]+…+[1]+[0].

繼續講前半部分劃分當i>k/3時,是乙個公差為2的等差數列,但需要注意的是,由於k/2

取整,所以其首項k%(k/2)可能為0也可能為2得等差數列,但需要注意的是,由於取整k/2取整,所以其首項k/(k%2)可能為0也可能為1。

需要注意的是,當拆分到1=#include

#include

using namespace std;

intmain()

cout<}}//遞迴演算法

#include

using namespace std;

int m,k;

intjosephus

(int m)

intmain()

這種演算法效率是極高的但還可以對它進行優化,使他與侯子數無關。

將上面的遞迴程式中的第12行進行注釋去除,再次編譯執行觀察輸出的ans值,例如當m=30,k=3時如表6.2所示

ans123

4567

891011值2

2141

4714

710ans…

2122

2324

2526

2728

2930值…

25811

1417

2023

2629

可以發現從ans21到30之間的值處於一種等差遞增的狀態。通過分析ans=(ans+k-1)%i+1,可以看出,當i比較大而ans+k-1比較小的時候,ans就處於一種公差為k的等差遞增狀態,而這一部分我們可以跳過。

設中間變數x列出等式:ans+k×x-1=i+x。

解出x,令ans=ans+k*x,將i+x直接賦值給i,這樣就跳過了中間共x重的迴圈,從而節省了等差遞增得時間開銷。

當然,我們還需要注意幾種特殊情況:

1 當k=1時,最終結果就是(k+n-1)%m。

2 當k!=1時,最終結果就是(k+n-1)%m;

參考程式如下所示:

#include

using namespace std;

intmain()

else

//該次跳躍可以執行到末尾

} ans=

(ans+k-1)

%i+1;}

cout

return0;

}

演算法分析:演算法優化之處就是通過觀察規律而得到的,其實就通過計算x的值,減少了迴圈當中一些不必要的輪次,從而大大的節省了時間,以至於演算法本身與m是沒有關係的。

約瑟夫問題(猴子選大王)

問題描述 約瑟夫問題 有 只猴子,按順時針方向圍成一圈選大王 編號從 到 從第 號開始報數,一直數到 數到 的猴子退出圈外,剩下的猴子再接著從1 開始報數。就這樣,直到圈內只剩下乙隻猴子時,這個猴子就是猴王,程式設計求輸入 後,輸出最後猴王的編號。輸入資料 每行是用空格分開的兩個整數,第乙個是 n,...

約瑟夫問題,猴子選大王

描述 約瑟夫問題 有 只猴子,按順時針方向圍成一圈選大王 編號從 到 從第 號開始報數,一直數到 數到 的猴子退出圈外,剩下的猴子再接著從1開始報數。就這樣,直到圈內只剩下乙隻猴子時,這個猴子就是猴王,程式設計求輸入 後,輸出最後猴王的編號。輸入每行是用空格分開的兩個整數,第乙個是 n,第二個是 m...

猴子選大王 約瑟夫問題

1.問題 一群猴子要選新猴王。新猴王的選擇方法是 讓n只候選猴子圍成一圈,從某位置起順序編號為1 n號。從第1號開始報數,每輪從1報到3,凡報到3的猴子即退出圈子,接著又從緊鄰的下乙隻猴子開始同樣的報數。如此不斷迴圈,最後剩下的乙隻猴子就選為猴王。請問是原來第幾號猴子當選猴王?輸入格式 輸入在一行中...