约瑟夫斯问题及其编程
来源:互联网 发布:java 驻场开发 编辑:程序博客网 时间:2024/06/02 06:23
约瑟夫斯(Josephus)问题是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。并且约瑟夫斯问题的描述是这样的:有n个囚犯站成一个圆圈,准备处决。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。
然后问题是,给定了n和k,一开始要站在什么地方才能避免被处决?
在约瑟夫斯问题里详细介绍了其中k=2时此问题的数学方式的解法,并得到了一个可以通过数学归纳法证明的定理:
如果且,则。
比较令人眼前一亮的是这个结论的表现形式竟与整数n的二进制表示有关:即把n的第一位移动到最后,便得到。如果n的二进制表示为,则。这点很容易证明:因n的第一位是1,并且其余位的十进制值就是l,然后左移一位(即2*l)再加上第一位的值就变成了的值了。
接着使用动态规划的方法得到一般情况下(即)的递推公式:
当n=1时,;
但n>1时,
此时先开始用数学方法来实现约瑟夫斯问题的编程,其代码如下(使用递推方式):
#include <iostream>using namespace std;int Josephus(int n, int k);int main(){ int n, k, ret; cout << "Please Enter Two number(n, k): "; cin >> n >> k; ret = Josephus(n, k); cout << "The final winner is " << ret << endl; system("pause"); return 0; } int Josephus(int n, int k) { int ret; if(1 == n) return ret = 1; else { ret = (Josephus(n-1, k) + k)%n; if(0 == ret) ret = n; return ret; } }
当输入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 <iostream>using namespace std;int main(){ int n, k, ret = 1, i; cout << "Please Enter Two Number(n, k): "; cin >> n >> k; for(i = 2; i <= n; i++) { ret = (ret + k)%i; if(0 == ret) ret = i; } cout << "The final winner is " << ret << endl; system("pause"); return 0; }
执行结果如下图所示:
接下来使用链表方法来实现:
这里解决这个问题的核心步骤(即程序的基本算法)是:
1)建立一个具有n个链接点而无头结点的循环链表;
2)确定第一个报数人的位置即m;
3)不断地从该链表中删除报数人处的链接点,直到该链表为空。
其代码如下:
#include <iostream>using namespace std;typedef struct node{ int data; struct node *next; }Node; void createList(Node* &head, Node* &tail, int n);void print(Node* &head);void countPrint(Node* &head, Node* &tail, int k);int main(){ Node *head, *tail; int n, k; cout << "Please Enter Two numbers(n, k): "; cin >> n >> k; createList(head, tail, n); print(head); countPrint(head, tail, k); system("pause"); return 0; } void createList(Node* &head, Node* &tail, int n){ if(n < 1) { head = NULL; return; } head = new Node; head->data = 1; head->next = NULL; Node *p = head; for(int i = 2; i < n+1; i++) { p->next = new Node; p = p->next; p->data = i; p->next = NULL; } tail = p; p->next = head; } void print(Node* &head){ Node *p = head; do { cout << " " << p->data << " "; p = p->next; }while(p != head); cout << "\n"; } void countPrint(Node* &head, Node* &tail, int k){ Node *cur = head; Node *pre = tail; int cnt = k; while(cur && cur != cur->next) { if(--cnt) { pre = cur; cur = cur->next; } else { pre->next = cur->next; cout << " " << cur->data << " "; delete cur; cur = pre->next; cnt = k; } } if(cur == cur->next) { cout << " " << cur->data << endl; delete cur; head = tail = NULL; } }执行结果如下图所示:
参考资料:http://blog.csdn.net/zhuimengzh/article/details/6727221
- 约瑟夫斯问题及其编程
- 约瑟夫问题及其变形
- 约瑟夫问题及其变形
- 约瑟夫问题及其各种优化
- Josephus约瑟夫问题及其变种
- 约瑟夫环问题及其尽可能的优化
- 模拟 - 约瑟夫环问题及其变式
- 编程实现约瑟夫环问题
- 在线编程--约瑟夫问题I
- 在线编程--约瑟夫问题II
- 约瑟夫环问题编程实现
- 编程实现约瑟夫环问题
- 约瑟夫斯问题
- 约瑟夫斯问题
- 约瑟夫斯问题
- (百例编程)71.约瑟夫问题
- 约瑟夫环的问题编程C++实现
- 约瑟夫环问题-C++编程实现
- Fiddler 教程(一)
- java解决中文乱码
- 弯管
- 道听途说(一)——见闻随笔
- iOS设计模式(01):观察者
- 约瑟夫斯问题及其编程
- 以后学习方向
- 在任意程序上使用PerfHUD
- php的字符串处理函数和js的字符串处理函数
- android中的对话框(AlertDialog)自动消失
- meteor.js
- perfHUD使用说明
- 取消actionbar左侧的快捷图标和文字
- Fiddler (二) Script 用法