如果真的按照題目中給定 \(n\) 的範圍,暴力模擬做法是不可行的,
然而貌似資料範圍沒有那麼大,所以可以逐圈模擬標記壞人;
另外,對於經典的約瑟夫問題,只需求出最後活下來的人的編號,
是可以用遞迴的方法 \(o(n)\) 解決的;
我們假設 \(f(n, m)\) 表示 \(n\) 個人依次報數報出 \(m\) 則被殺死時,
最終活下來的人的編號,為方便討論,從 \(0\) 開始編號,
先不妨假設 \(m <= n\),則第一輪報數,\(m - 1\) 被殺死,
\(m\) 可看成問題規模為 \(n - 1\) 時,編號為 \(0\) 的人,
那麼在問題規模為 \(n\) 時最終活下來的人編號為 \(m + f(n - 1, m)\),
此外還需取模保證答案在 \([0, n)\);
如果 \(m > n\),那麼第乙個被殺死的人編號為 \(m \% n - 1\),
於是答案為 \(m \% n + f(n - 1, m)\),
整理後可知,\(f(n, m) = (m + f(n - 1, m)) \% n\);
而當 \(n = 2\) 時,若 \(m\) 為偶數則答案為 \(0\),若 \(m\) 為奇數則答案為 \(1\)。
實際上,如果規定 \(n = 1\) 時,答案為 \(0\)(初始狀態就剩下 \(0\) 乙個人),
也能根據上述遞迴公式推出 \(n = 2\) 時的答案。
上述解法依然可以繼續優化,
如果 \(m + f(n - 1, m)\) 不超過 \(n\),則不必取模,
那麼我們其實可以通過遞推的做法,每次從 \(1\) 到 \(n\) 列舉問題規模,
如果不需要取模,則不必依次列舉,而是可以跳躍著增長問題規模,
具體來說,答案每次增加 \(m\),而問題規模每次增加 \(1\),
二者差距每次縮小 \(m - 1\),則可計算得出每次能直接增加的問題規模大小。
點選展開
#include #include using namespace std;
vectorperson;
int main()
for (int i = 0, j = 0; i < 2 * n; ++i)
puts("\n");
}return 0;
}
HDU 4841 圓桌問題
acm模版 這個題簡單的來就是暴力列舉約瑟夫環,當然,太暴力也不好,適當的用資料結構優化一下也是有必要的,這裡用向量維護,成功水過。include include include include include using namespace std const int maxn 4e4 const...
hdu4841 圓桌問題
圓桌上圍坐著2n個人。其中n個人是好人,另外n個人是壞人。如果從第乙個人開始數數,數到第m個人,則立即處死該人 然後從被處死的人之後開始數數,再將數到的第m個人處死 依此方法不斷處死圍坐在圓桌上的人。試問預先應如何安排這些好人與壞人的座位,能使得在處死n個人之後,圓桌上圍坐的剩餘的n個人全是好人。多...
HDU 4841 圓桌問題
圓桌上圍坐著2n個人。其中n個人是好人,另外n個人是壞人。如果從第乙個人開始數數,數到第m個人,則立即處死該人 然後從被處死的人之後開始數數,再將數到的第m個人處死 依此方法不斷處死圍坐在圓桌上的人。試問預先應如何安排這些好人與壞人的座位,能使得在處死n個人之後,圓桌上圍坐的剩餘的n個人全是好人。i...