約瑟夫問題(優化優化再優化)

2021-09-09 03:03:41 字數 2816 閱讀 3125

約瑟夫環是乙個數學的應用問題:已知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。

現在我們把他們的編號做一下轉換:

1k --> 0

2k+1 --> 1

3k+2 --> 2

4...

5...

6k-2 --> n-2

7k-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]。

遞推公式:

1f[1]=0;

2f[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矩陣...