然後問題是,給定了n和k,一開始要站在什麼地方才能避免被處決?
在約瑟夫斯問題裡詳細介紹了其中k=2時此問題的數學方式的解法,並得到了乙個可以通過數學歸納法證明的定理:
如果比較令人眼前一亮的是這個結論的表現形式竟與整數n的二進位制表示有關:即把n
的第一位移動到最後,便得到
的二進位制表示為
接著使用動態規劃的方法得到一般情況下(即
當n=1時,
但n>1時,
#include using namespace std;
int josephus(int n, int k);
int main()
int josephus(int n, int k)
}
當輸入n=9、k=5時最後乙個數是8,下圖就是執行的結果:
注意:這裡必須要對josephus(n, k)的值進行判斷,因josephus(n-1, k)+k>=k>0,所以當josephus(n, k)為0時,必須要將其賦值為n。(為什麼是n而不是n*m?其中m是大於1的任意正整數)
例如注釋掉上述**中的這段**:if(0 == ret) ret = n;
執行的結果如下所示:
此時結果是錯誤的,最後留下來的人應該是9才對。
同時這裡的遞推可以用迴圈來實現:
#include using namespace std;
int main()
cout << "the final winner is " << ret << endl;
system("pause");
return 0;
}
執行結果如下圖所示:
這裡解決這個問題的核心步驟(即程式的基本演算法)是:
1)建立乙個具有n個鏈結點而無頭結點的迴圈鍊錶;
2)確定第乙個報數人的位置即m;
3)不斷地從該鍊錶中刪除報數人處的鏈結點,直到該鍊錶為空。
其**如下:
#include using namespace std;
typedef struct node
node;
void createlist(node* &head, node* &tail, int n);
void print(node* &head);
void countprint(node* &head, node* &tail, int k);
int main()
void createlist(node* &head, node* &tail, int n)
head = new node;
head->data = 1;
head->next = null;
node *p = head;
for(int i = 2; i < n+1; i++)
tail = p;
p->next = head;
}void print(node* &head)
while(p != head);
cout << "\n";
}void countprint(node* &head, node* &tail, int k)
else
}if(cur == cur->next)
}
執行結果如下圖所示:
約瑟夫斯問題
有n個人圍成一圈,報數從1到m依次迴圈報數,報到m的就退出 死 現在我們來看遞推,由於為了方便表示 s m i 0的情況,我們讓第一人的編號為0,從一開始也可以 既然你問遞推,那步驟就不說了,只說這個公式吧 讓獲勝者的編號為0 最後乙個人只有他了當然是0 f i 表示獲勝者在剩下i個人時的那一局的編...
約瑟夫斯問題 關於約瑟夫斯問題的反饋
約瑟夫斯問題 我上週的文章是關於解決kotlin的約瑟夫斯問題的。為了便於比較,這是我最初編寫的版本 class soldier val position int fun isdead state state dead enum class state class circle private va...
約瑟夫問題及其變形
問題 n個數排乙個圈,從編號1開始刪除,以後每m個數刪一次,問最後乙個被刪除的數。2 n 10000,1 k 10000 includeusing namespace std int main return 0 變形 從第k個數開始刪。includeusing namespace std defin...