问题描述:皇帝决定找出全国中最幸运的一个人,于是从全国选拔出 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)相关推荐

  1. PTA 线性表 7-1 约瑟夫环(Josephus)问题(by Yan) (100分) 按出列次序输出每个人的编号

    7-1 约瑟夫环(Josephus)问题(by Yan) (100分) 编号为1,2,-,n的n个人按顺时针方向围坐在一张圆桌周围,每人持有一个密码(正整数).一开始任选一个正整数m作为报数上限值,从 ...

  2. 约瑟夫环(Josephus Circle)

    目录 一.问题描述 二.用数组求解 三.用递归求解 一.问题描述 约瑟夫环(Josephus Circle)是一个数学的应用问题:已知 n 个人(分别用编号 0, 1, 2, ..., n - 1 表 ...

  3. 组合数学--约瑟夫环问题 Josephus

    约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,类似问题又称为约瑟夫环. 有n个囚犯站成一个圆圈,准备处决.首先从一个人开始,越过k-2个人(因为第 ...

  4. 【数据结构与算法】 01 链表 (单链表、双向链表、循环链表、块状链表、头结点、链表反转与排序、约瑟夫环问题)

    一.线性表 1.1 概念与特点 1.2 线性表的存储结构 1.3 常见操作 1.4 应用场景 二.链表 2.1 链表简介 2.2 单向链表(单链表) 2.21 基本概念 2.22 单链表基本操作 2. ...

  5. 求约瑟夫环问题最后胜利者的一般解法以及数学推导方法

    问题描述: 约瑟夫环问题(Josephus) 用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出.写出C程序. 解法一: 思路:建立一个有N个元素的循环链表,然后从链表表头遍 ...

  6. 动态规划解决约瑟夫环问题

    题目: 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号0,1,2,3-n-1分别表示)围坐在一张圆桌周围.从编号为0的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m ...

  7. 约瑟夫环问题(数学方法)

    问题描述: 约瑟夫环问题(Josephus) 用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出.写出C程序. 解法一: 思路:建立一个有N个元素的循环链表,然后从链表表头遍 ...

  8. LightOJ - 1179 Josephus Problem(约瑟夫环)

    题目链接:https://vjudge.net/contest/28079#problem/G 题目大意:约瑟夫环问题,给你n和k(分别代表总人数和每次要数到k),求最后一个人的位置. 解题思路:因为 ...

  9. UVA1363 LA3521 POJ2800 ZOJ2646 Joseph‘s Problem【约瑟夫环+数学】

    Joseph's Problem Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7906 Accepted: 2107 Desc ...

  10. I00032 约瑟夫环(Joseph problem)

    有关约瑟夫环的介绍,可以参见百度百科的约瑟夫环. 程序中假定人数n小于100,输入数据为n和m.其中,n为人数,数到第m个人出局.输出出局人的顺序.输入数据为0和0时程序结束. AC的C语言程序如下: ...

最新文章

  1. CentOs7中安装python3.7.6
  2. SpringBoot+tomcat+web
  3. qt opencv cmake配置 单纯小白
  4. Android之ProgressBar读取文件进度解析
  5. [reference]-Features_in_A-profile
  6. JavaScript权威指南--多媒体和图形编程
  7. 后盾网php多少钱_商标转让做公证花多少钱-购店网
  8. 《信息熵,联合熵,条件熵,交叉熵,相对熵》
  9. 【kafka】Flink 消费 kafka Received unknown topic topic/partition may not exist Describe access to it
  10. [转]Vue基于vue-quill-editor富文本编辑器使用心得
  11. STM32单片机跑马灯实验解析
  12. 思科模拟器-实验 18 三层交换访问控制列表配置
  13. RFID和NFC的区别 以及门禁卡和饭卡
  14. Markdown 4 印象笔记之马克飞象
  15. 3dmax制作光束效果教程!
  16. Python自动抢红包,从此再也不会错过微信红包了!
  17. 高性能RTMP推流服务器软件EasyDSS如何支持推流摄像机推流直播进行云端录像存储及计划保存
  18. 谷歌浏览器翻译英文网页功能消失解决方案
  19. linux停止tomcat 8005,严重:无法联系localhost:8005.关闭tomcat服务器时,Tomcat可能没有运行错误....
  20. JAVA实现闹钟提醒功能_AlarmManager类的应用(实现闹钟功能)

热门文章

  1. http://blog.csdn.net/evankaka/article/details/45155047
  2. Spring Boot 定时任务,怎么实现任务动态增删启停?
  3. 图解 SpringCloud 体系!
  4. Facebook提高工作效率的秘密 ,值得收藏
  5. “陆奇争夺战”:江湖传言,得陆奇者得AI天下。
  6. 阿里技术专家带你使用Spring框架快速搭建Web工程项目
  7. Android性能优化系列---管理你的app内存(一)
  8. Go语言构建高并发分布式系统实践
  9. Python 密集知识点汇总
  10. 使用 shell 在多服务器上批量操作