約瑟夫問題(連結串列經典)
阿新 • • 發佈:2019-02-14
約瑟夫問題
總時間限制: 1000ms記憶體限制: 65536kB
描述約瑟夫問題:有n只猴子,按順時針方向圍成一圈選大王(編號從1到n),從第1號開始報數,一直數到m,數到m的猴子退出圈外,剩下的猴子再接著從1開始報數。就這樣,直到圈內只剩下一隻猴子時,這個猴子就是猴王,程式設計求輸入n,m後,輸出最後猴王的編號。
輸入每行是用空格分開的兩個整數,第一個是 n,第二個是 m ( 0 < m,n <=300)。最後一行是:0
0
輸出對於每行輸入資料(最後一行除外),輸出資料也是一行,即最後猴王的編號樣例輸入
6 2
12 4
8 3
0 0
樣例輸出
5
1
7
解析:這是一個很經典(經典就代表這道題是圍繞著連結串列的核心展開)的連結串列問題,當然也可以不用連結串列來做。
首先要注意幾點:
1.題目的要求是要圍成一個圈,所以要有一點技巧處理:將最後一個的下一個指向第一個
2.每次踢出一個猴砸之後,都是從踢出的那個猴砸的下一個開始,而不是重新從第一個開始。(當時我就是因為這裡理解錯了一直沒做出來,讀題不仔細!)
大致思路:
1.先要定義一個結構體,為其建立一個連結串列。
2.然後是要寫兩個函式:1個是用來表示總猴砸數的改變,一個是用來表示報數猴砸的。
3.主函式就是讀入資料,然後進入函式操作。
下面是程式碼:
#include using namespace std; int n,m; struct node{ //首先定義一個結構體 int n; node *next,*ahead; //使用兩個指標為結點分配其位置 }; node*ahead;node*tail; void create(node* &head,int &n){ //第一個函式是用來表示所剩總猴子數的 node* tail=head; for(int i=1;i<=n;i++){ //開始從第一個迴圈 node* unit=new node; //定義一個新的結點 unit->n=i; //移動結點 tail->next=unit; tail=unit; } head=head->next; //每次都要移動開始的那一個 tail->next=new node; //因為開始的移動了,所以結尾的下一個也要移動到新的第一個去,形成一個環 node* unit=head; for(int i=1;i<=n;i++){ unit->next->ahead=unit; //相當與插入一個結點 unit=unit->next; //移動這個結點 } tail->next=head; //tips:技巧處理:將收尾連線,形成一個環 head->ahead=tail; } void s(node* &head,int &m){ //第二個函式是用來表示報數的猴子的 int x=n-1;int k=0; node* unit=head; while(x){ k++; if(k==m){ unit->ahead->next=unit->next;//這裡是刪除一個結點的意思 unit->next->ahead=unit->ahead; k=0; x--; } unit=unit->next; } cout<n<>n>>m; //輸入猴子數n和所數到的那個數將會被退出圈子的數m while(n!=0||m!=0){ //滿足條件就執行上面的函式 node*head=new node; create(head,n); s(head,m); cin>>n>>m; } return 0; }