约瑟夫(环)问题(Josephus problem)
问题描述:皇帝决定找出全国中最幸运的一个人,于是从全国选拔出 n 个很幸运的人,让这 n 个人围着圆桌进餐,可是怎么选择出其中最幸运的一个人呢?皇帝决定:从其中一个人从 1 开始报数,按顺序数到第 k 个数的人自动出局,然后下一个人从 1 开始报数,数到 k 的人出局……。如此直到最后只剩下约瑟夫一人,然后他就成为全国最幸运的人。请问约瑟夫最初的位置?(注:原问题略显暴力,故自创此趣味题目)
分析:把第一个开始报 1 的人标定为 1,然后按报数顺序依次标定其余的人为:2,3,……,n - 1,n。按规则进行淘汰,直到最后剩一个数字,这个数字就是约瑟夫的位置。
解决方案:
1. 模拟法(simulation)
数组模拟,时间复杂度最高为 O(n3) (当k≈n时 ) ,空间复杂度O(n)
1 /********** 用数组模拟 *************/ 2 void findNext(bool *out, int n, int &curPosition){ 3 if(!out[curPosition]) { 4 int pNext = (curPosition + 1) % n; 5 if(!out[pNext]) 6 curPosition = pNext; 7 else{ 8 curPosition = pNext; 9 while(out[curPosition]) 10 curPosition = (curPosition + 1) % n; 11 } 12 }else 13 { 14 while(out[curPosition]) 15 curPosition = (curPosition + 1) % n; 16 } 17 } 18 int josephus(int n, int k) 19 { 20 if(n < 1 || k < 0) return -1; 21 if(n == 1) return n; 22 bool *out = new bool[n]; /********* 记录是否出局 *********/ 23 for(int i = 0; i < n; ++i) 24 out[i] = false; 25 int current = 0; 26 int n2 = n; 27 while(n2 != 1) 28 { 29 int cnt = k; 30 while(--cnt) 31 findNext(out, n, current); 32 out[current] = true; 33 findNext(out, n, current); 34 --n2; 35 } 36 delete[] out; 37 out = NULL; 38 return (current + 1); 39 }
Code
循环链表模拟:时间复杂度O(n),空间复杂度O(n)
/********** 循环链表 *************/
struct ListNode{int val;ListNode * next;ListNode(int x):val(x), next(NULL) {}
};int josephus(int n, int k)
{if(n < 1 || k < 1)return -1;if(n == 1) return n;ListNode *head = new ListNode(1);ListNode *prior = head; for(int i = 2; i <= n; ++i){ListNode *tem= new ListNode(i);prior->next = tem;prior = prior->next;}prior->next = head;while(head->next != head){int cnt = k;while(--cnt){head = head->next;prior = prior->next;}prior->next = prior->next->next;ListNode *current = head; head = head->next;delete current; /*** 只释放堆内存空间,局部指针自动回收 ***/}return head->val;
}
2.建模法(modeling)
使用队列建模。
1 /********** 用队列(注:使用STL可简单化) *************/ 2 bool ERROR = false; 3 typedef int ELEM; 4 struct Node{ 5 ELEM val; 6 Node *next; 7 Node(ELEM e):val(e), next(NULL){} 8 }; 9 struct queue{ 10 queue():front(NULL), tail(NULL) {} 11 ELEM pop(); 12 void push(ELEM val); 13 bool empty(); 14 private: 15 Node *front; 16 Node *tail; 17 18 }; 19 ELEM queue::pop(){ 20 if(front == NULL){ 21 ERROR = true; 22 return -1; 23 }else{ 24 ELEM v = front->val; 25 front = front->next; 26 return v; 27 } 28 } 29 void queue::push(ELEM val){ 30 Node *p = new Node(val); 31 if(front == NULL) 32 front = tail = p; 33 else 34 { 35 tail->next = p; 36 tail = tail->next; 37 } 38 } 39 bool queue::empty(){ 40 if(front == NULL) 41 return true; 42 else 43 return false; 44 } 45 46 int josephus(int n, int k) 47 { 48 if(n < 1 || k < 1) return -1; 49 if(n == 1) return 1; 50 queue qu; 51 for(int i = 1; i <= n; ++i) 52 qu.push(i); 53 int result = 0; 54 while(!qu.empty()) 55 { 56 for(int i = 1; i <= k-1; ++i) 57 qu.push(qu.pop()); 58 result = qu.pop(); 59 } 60 return result; 61 }
Code
3. 数学推理 && 动态规划
初始:0 1 ... (k-2) (k-1) k ... (N-1)
K 出局: 新的顺序:
k 0
... p ...
N-1 映 N - k - 1 P(x) = (x - k + N) mod N
0 射 N - k 令:y = P(x) = (x - k + N) mod N
1 N - k + 1 则,x = (y + k - N) mod N
... ... = (y + k) mod N
k-2 N - 2 P-1(x) = (x + k) mod N
设 f(N,k) 为最后所得的数字,则:
f(N,k) = P-1( f(N-1,k) ) = (f(N-1,k) + k) mod N
所以有如下递推公式:
int josephus(int n, int k)
{if(n < 1 || k < 1) return -1;if(n == 1) return 1;int result = 0;for(int i = 2; i <= n; ++i)result = (result + k) % i; return result+1;
}
另外,简洁的递归:(不推荐,递归栈太小,容易溢出)
int josephus(int n, int k)
{if(n < 1 || k < 1) return -1;if(n == 1) return 1;elsereturn ((josephus(n - 1, k) + k - 1) % n + 1);
}
最后,当 k = 2 时,如下公式可直接求出:
代码为:
int n = 1000;
cout<< 2*(n - pow(2.0, int(log((float)n) / log((float)2))))+1 <<endl;
转载于:https://www.cnblogs.com/liyangguang1988/p/3620007.html
约瑟夫(环)问题(Josephus problem)相关推荐
- PTA 线性表 7-1 约瑟夫环(Josephus)问题(by Yan) (100分) 按出列次序输出每个人的编号
7-1 约瑟夫环(Josephus)问题(by Yan) (100分) 编号为1,2,-,n的n个人按顺时针方向围坐在一张圆桌周围,每人持有一个密码(正整数).一开始任选一个正整数m作为报数上限值,从 ...
- 约瑟夫环(Josephus Circle)
目录 一.问题描述 二.用数组求解 三.用递归求解 一.问题描述 约瑟夫环(Josephus Circle)是一个数学的应用问题:已知 n 个人(分别用编号 0, 1, 2, ..., n - 1 表 ...
- 组合数学--约瑟夫环问题 Josephus
约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,类似问题又称为约瑟夫环. 有n个囚犯站成一个圆圈,准备处决.首先从一个人开始,越过k-2个人(因为第 ...
- 【数据结构与算法】 01 链表 (单链表、双向链表、循环链表、块状链表、头结点、链表反转与排序、约瑟夫环问题)
一.线性表 1.1 概念与特点 1.2 线性表的存储结构 1.3 常见操作 1.4 应用场景 二.链表 2.1 链表简介 2.2 单向链表(单链表) 2.21 基本概念 2.22 单链表基本操作 2. ...
- 求约瑟夫环问题最后胜利者的一般解法以及数学推导方法
问题描述: 约瑟夫环问题(Josephus) 用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出.写出C程序. 解法一: 思路:建立一个有N个元素的循环链表,然后从链表表头遍 ...
- 动态规划解决约瑟夫环问题
题目: 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号0,1,2,3-n-1分别表示)围坐在一张圆桌周围.从编号为0的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m ...
- 约瑟夫环问题(数学方法)
问题描述: 约瑟夫环问题(Josephus) 用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出.写出C程序. 解法一: 思路:建立一个有N个元素的循环链表,然后从链表表头遍 ...
- LightOJ - 1179 Josephus Problem(约瑟夫环)
题目链接:https://vjudge.net/contest/28079#problem/G 题目大意:约瑟夫环问题,给你n和k(分别代表总人数和每次要数到k),求最后一个人的位置. 解题思路:因为 ...
- UVA1363 LA3521 POJ2800 ZOJ2646 Joseph‘s Problem【约瑟夫环+数学】
Joseph's Problem Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7906 Accepted: 2107 Desc ...
- I00032 约瑟夫环(Joseph problem)
有关约瑟夫环的介绍,可以参见百度百科的约瑟夫环. 程序中假定人数n小于100,输入数据为n和m.其中,n为人数,数到第m个人出局.输出出局人的顺序.输入数据为0和0时程序结束. AC的C语言程序如下: ...
最新文章
- CentOs7中安装python3.7.6
- SpringBoot+tomcat+web
- qt opencv cmake配置 单纯小白
- Android之ProgressBar读取文件进度解析
- [reference]-Features_in_A-profile
- JavaScript权威指南--多媒体和图形编程
- 后盾网php多少钱_商标转让做公证花多少钱-购店网
- 《信息熵,联合熵,条件熵,交叉熵,相对熵》
- 【kafka】Flink 消费 kafka Received unknown topic topic/partition may not exist Describe access to it
- [转]Vue基于vue-quill-editor富文本编辑器使用心得
- STM32单片机跑马灯实验解析
- 思科模拟器-实验 18 三层交换访问控制列表配置
- RFID和NFC的区别 以及门禁卡和饭卡
- Markdown 4 印象笔记之马克飞象
- 3dmax制作光束效果教程!
- Python自动抢红包,从此再也不会错过微信红包了!
- 高性能RTMP推流服务器软件EasyDSS如何支持推流摄像机推流直播进行云端录像存储及计划保存
- 谷歌浏览器翻译英文网页功能消失解决方案
- linux停止tomcat 8005,严重:无法联系localhost:8005.关闭tomcat服务器时,Tomcat可能没有运行错误....
- JAVA实现闹钟提醒功能_AlarmManager类的应用(实现闹钟功能)
热门文章
- http://blog.csdn.net/evankaka/article/details/45155047
- Spring Boot 定时任务,怎么实现任务动态增删启停?
- 图解 SpringCloud 体系!
- Facebook提高工作效率的秘密 ,值得收藏
- “陆奇争夺战”:江湖传言,得陆奇者得AI天下。
- 阿里技术专家带你使用Spring框架快速搭建Web工程项目
- Android性能优化系列---管理你的app内存(一)
- Go语言构建高并发分布式系统实践
- Python 密集知识点汇总
- 使用 shell 在多服务器上批量操作