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

相关文章: