【例題描述】
由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的猴子即退出圈子,接著又從緊鄰的下乙隻猴子開始同樣的報數。如此不斷迴圈,最後剩下的乙隻猴子就選為猴王。請問是原來第幾號猴子當選猴王?輸入格式 輸入在一行中...