問題描述:
已知n個人(以編號1,2,3…n分別表示)圍坐在一張圓桌周圍。從編號為1的人開始報數,數到m的那個人出列;他的下乙個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到圓桌周圍的人全部出列,求最後乙個出列人的編號。
該問題可以用陣列或者迴圈鍊錶模擬,因為都是直接模擬,需要迴圈n次,每次數m次,所以時間複雜度都是o(n*m)。雖然複雜度比o(n)大,但是可以求出出圈的編號順序。也正是因為該方法將每次出圈的人都找了出來,所以做了很多無用操作,複雜度才會高達o(n*m)。
下面是陣列和鍊錶方法的**:
題意:n個人,從第k個人開始數1,數到m的人剔除,輸出剔除的順序。
#include
#include
#include
#include
#include
using
namespace
std;
#define maxn 10000
int a[maxn];
int n,k,m;
bool incircle[maxn];
typedef
struct _nodenode;
node* makedll(int n)
return head;
}void josephdll(node* head, int k, int m)
/*delete operation,begin*/
q = nodetodelete->next;
q->prev = nodetodelete->prev;
nodetodelete->prev->next = q;
printf("%d ",nodetodelete->number);
if(nodetodelete == head)
free(nodetodelete);
/*delete operation,end*/
nodetodelete = q;/*count from the next node*/
}printf("%d\n",head->number);
}void josepharr()
i--;
cout
<1)<
incircle[i%(n+1)]=0;/*delete the member i%(n+1) from the circle*/
}}int main()
cout
<
josepharr();/*base on the array*/
for(int i=1;i<=n;i++)
node* head;
head = makedll(n);
cout
josephdll(head,k,m);/*base on the doubly linked lists*/
return
0;}
o(n)方法運用動態規劃,或者說遞推,或者說找規律,都行吧。雖然複雜度低,但是不能求出出圈的順序。如果需要求出出圈的順序,複雜度依然是o(n*m)。
該方法遞推公式網上很多都能找到,但是卻極少人給出遞推過程。
我們發現,當從圈出來乙個人之後,後乙個人需要從1開始重新計數直到計到m。例如有n個人(1,2,3,… ,n-2,n-1),第m個人出來之後,需要從第m+1開計數。如果從m+1個人重新編號(即m+1個人編號為0,m+1為2,… …),那麼對剩下的n-1個人的操作跟開始有n個人的時候操作就是一樣的。
這就是可以運用動態規劃的原因:n的情況跟n-1的情況存在著某種關係。而我們只需用動態方程將這種關係表達出來,問題就可以解決。
下面顯示了如何進行重新編號:
設n個人圍成乙個圈的時候出列是第x』號,n-1個人圍成乙個圈的時候出列的是x號,並假設x已經求出來,那麼根據上面的遞推公式就可以反推求x』: 因為x=(x』*n+n-m)%n=x』*n%n+n%n-m%n=x』-m%n
所以x』=x+m%n=(x+m)%n
如果定義:dp[n]表示圈裡有n個人的時候最後剩下那個人的編號,答案就是dp[n]。
那麼就有dp[n]=(dp[n-1]+m)%n
但是dp[n-1]並不知道,所以dp[n]也沒法求出。當然dp[n-1]也需要通過動態方程求出:
dp[n-1]=(dp[n-2]+m)%n。
同樣dp[n-2],dp[n-3]….分別需要用dp[n-3],dp[n-4]求出。
最後dp[2]需要dp[1]求出,然而dp[1]=0是已知的。
所以從dp[2]開始依次可以求出dp[2],dp[3],dp[4]…dp[n]。
那麼問題就解決了。
#include
#include
#include
#include
#include
using
namespace
std;
#define maxn 10000
int dp[maxn];
int joseph(int m, int n)
return dp[n];
}int main()
約瑟夫環演算法
約瑟夫環是乙個數學的應用問題 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。2b求解 private void myjosf int teamle...
演算法 約瑟夫環
已知n個人 以編號1,2,3 n分別表示 圍坐在一張圓桌周圍 使用 list 來模擬環結構,不被淘汰則將其加入到 list 尾部,淘汰的直接移除。需注意,以編號 k 為第乙個報數的人,需要調整其在報數正式開啟前到 list 的頭部。param n 人的總數 param k 開始報數的序號,1 k n...
約瑟夫環問題詳解
講乙個比較有意思的故事 約瑟夫是猶太軍隊的乙個將軍,在反抗羅馬的起義中,他所率領的軍隊被擊潰,只剩下殘餘的部隊40餘人,他們都是寧死不屈的人,所以不願投降做叛徒。一群人表決說要死,所以用一種策略來先後殺死所有人。於是約瑟夫建議 每次由其他兩人一起殺死乙個人,而被殺的人的先後順序是由抽籤決定的,約瑟夫...