約瑟夫環是乙個數學的應用問題:已知n個人(以編號1,2,3...n分別表示)圍坐在一張圓桌周圍。
從編號為k的人開始報數,數到m的那個人出列;他的下乙個人又從1開始報數,數到m的那個人又出列;
依此規律重複下去,直到圓桌周圍的人全部出列。
1、模擬方法
2、數學方法
模擬方法就是所謂的乙個個模擬,乙個乙個出列。這個方法比較多,可以直接用陣列模擬,也可以直接建乙個迴圈鍊錶模擬,
總之這個很好實現,但是複雜度卻是o(nm),如果n和m都是10000,要求1s計算出結果,估計就不行了。
這個演算法實現,網上一大堆:隨便給出兩個:
struct listnode
};
//自定義鍊錶實現
int josephusproblem_solution1(int n, int m)
pcurrentnode->next = phead;
//迴圈遍歷
plastnode = pcurrentnode;
pcurrentnode = phead;
while(pcurrentnode->next != pcurrentnode)
//刪除報到m - 1的數
plastnode->next = pcurrentnode->next;
delete pcurrentnode;
pcurrentnode = plastnode->next;
} //釋放空間
int result = pcurrentnode->num;
delete pcurrentnode;
return result;
}
//使用標準庫
int josephusproblem_solution2(int n, int m)
//臨時儲存刪除的結點
list::iterator iterdel = itercurrent;
if(++itercurrent == listint.end())
itercurrent = listint.begin();
//刪除結點
listint.erase(iterdel);
} return *itercurrent;
}
由於上面o(nm)的方法很容易超時,所以這裡的數學方法可以做到o(n).
問題描述:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求勝利者的編號。
我們知道第乙個人(編號一定是m%n-1) 出列之後,剩下的n-1個人組成了乙個新的約瑟夫環(以編號為k=m%n的人開始): k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2,並且從k開始報0。
現在我們把他們的編號做一下轉換:
1
k --> 0
2
k+1 --> 1
3
k+2 --> 2
4
...
5
...
6
k-2 --> n-2
7
k-1 --> n-1
變換後就完完全全成為了(n-1)個人報數的子問題,假如我們知道這個子問題的解:例如x是最終的勝利者,那麼根據上面這個表把這個x變回去不剛好就是n個人情況的解嗎?!!變回去的公式很簡單,相信大家都可以推出來:x'=(x+k)%n。
如何知道(n-1)個人報數的問題的解?對,只要知道(n-2)個人的解就行了。(n-2)個人的解呢?當然是先求(n-3)的情況 ---- 這顯然就是乙個倒推問題!好了,思路出來了,下面寫遞推公式:
令f[i]表示i個人玩遊戲報m退出最後勝利者的編號,最後的結果自然是f[n]。
遞推公式:
1
f[1]=0;
2
f[i]=(f[i-1]+m)%i; (i>1)
有了這個公式,我們要做的就是從1-n順序算出f[i]的數值,最後結果是f[n]。因為實際生活中編號總是從1開始,我們輸出f[n]+1。
int f(int n, int m)
return f2+ 1;
}
今天碰到乙個題目,n <= 10^18,m<=1000,時間1s,這想想o(n)肯定超時,沒得說。
但是我麼可以看看上面的規律,
f[i] = (f[i-1]+m)%i,通過這個式子,我們發現,到一定程度,m會遠遠小於i的,所以每次不是僅僅加乙個m,我可以一下子加x*m,從而跳過x個i,事實證明,這樣做的效率非常高。
當然只有當m遠遠小於n的時候,效率會比較高。如果m>n那麼效率也就接近o(n)了。
對於當前的i,如果f1+m
什麼時候結束呢?
如果i+x>=n,那麼就證明這次已經超過了n,這裡只需要令f2=f1+(n-i)*m,並且i=n跳出迴圈即可。
具體**及注釋如下:
#include using namespace std;
//資料範圍n<=10^18,m<=1000,時間幾十ms
__int64 n,m;
int main()
} cout << f2+1 <
約瑟夫優化
writefile ysf.py defmove players,step num step 1while num 0 tmp players.pop 0 num num 1return players defplay players,step,alive 模擬約瑟夫問題的函式 input play...
約瑟夫環的數學優化
首先,約瑟夫環的數學優化方法為 為了討論方便,先把問題稍微改變一下,並不影響原意 問題描述 n個人 編號0 n 1 從0開始報數,報到 m 1 的退出,剩下的人繼續從0開始報數。求勝利者的編號。我們知道第乙個人 編號一定是 m 1 n 出列之後,剩下的n 1個人組成了乙個新的約瑟夫環 以編號為k m...
優化問題,凸優化,凸二次優化問題
首先 優化問題通常喜歡求解最小值min 如果要求max就給他轉換過來 如何來判斷乙個函式是否是凸函式呢?對於一元函式f x 我們可以通過其二階導數f x 的符號來判斷。如果函式的二階導數總是非負,即f x 0 則f x 是凸函式對於多元函式f x 我們可以通過其hessian矩陣 hessian矩陣...