约瑟夫(环)问题(Josephus problem)
问题描述:皇帝决定找出全国中最幸运的一个人,于是从全国选拔出 n 个很幸运的人,让这 n 个人围着圆桌进餐,可是怎么选择出其中最幸运的一个人呢?皇帝决定:从其中一个人从 1 开始报数,按顺序数到第 k 个数的人自动出局,然后下一个人从 1 开始报数,数到 k 的人出局……。如此直到最后只剩下约瑟夫一人,然后他就成为全国最幸运的人。请问约瑟夫最初的位置?(注:原问题略显暴力,故自创此趣味题目)
分析:把第一个开始报 1 的人标定为 1,然后按报数顺序依次标定其余的人为:2,3,……,n - 1,n。按规则进行淘汰,直到最后剩一个数字,这个数字就是约瑟夫的位置。
解决方案:
1. 模拟法(simulation)
数组模拟,时间复杂度最高为 O(n3) (当k≈n时 ) ,空间复杂度O(n)
/********** 用数组模拟 *************/
void findNext(bool *out, int n, int &curPosition){
if(!out[curPosition]) {
int pNext = (curPosition + ) % n;
if(!out[pNext])
curPosition = pNext;
else{
curPosition = pNext;
while(out[curPosition])
curPosition = (curPosition + ) % n;
}
}else
{
while(out[curPosition])
curPosition = (curPosition + ) % n;
}
}
int josephus(int n, int k)
{
if(n < || k < ) return -;
if(n == ) return n;
bool *out = new bool[n]; /********* 记录是否出局 *********/
for(int i = ; i < n; ++i)
out[i] = false;
int current = ;
int n2 = n;
while(n2 != )
{
int cnt = k;
while(--cnt)
findNext(out, n, current);
out[current] = true;
findNext(out, n, current);
--n2;
}
delete[] out;
out = NULL;
return (current + );
}
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)
使用队列建模。
/********** 用队列(注:使用STL可简单化) *************/
bool ERROR = false;
typedef int ELEM;
struct Node{
ELEM val;
Node *next;
Node(ELEM e):val(e), next(NULL){}
};
struct queue{
queue():front(NULL), tail(NULL) {}
ELEM pop();
void push(ELEM val);
bool empty();
private:
Node *front;
Node *tail; };
ELEM queue::pop(){
if(front == NULL){
ERROR = true;
return -;
}else{
ELEM v = front->val;
front = front->next;
return v;
}
}
void queue::push(ELEM val){
Node *p = new Node(val);
if(front == NULL)
front = tail = p;
else
{
tail->next = p;
tail = tail->next;
}
}
bool queue::empty(){
if(front == NULL)
return true;
else
return false;
} int josephus(int n, int k)
{
if(n < || k < ) return -;
if(n == ) return ;
queue qu;
for(int i = ; i <= n; ++i)
qu.push(i);
int result = ;
while(!qu.empty())
{
for(int i = ; i <= k-; ++i)
qu.push(qu.pop());
result = qu.pop();
}
return result;
}
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;
else
return ((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;
约瑟夫(环)问题(Josephus problem)的更多相关文章
- 约瑟夫环问题(Josephus)
约瑟夫环:用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至最后一个元素并输出该元素的值. 一.循环链表:建立一个有N个元素的循环链表,然后从链表头开始遍历并记数,如果计数值为M,则 ...
- 组合数学--约瑟夫环问题 Josephus
约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,类似问题又称为约瑟夫环. 有n个囚犯站成一个圆圈,准备处决.首先从一个人开始,越过k-2个人(因为第 ...
- 约瑟夫问题(Josephus Problem)的两种快速递归算法
博文链接:http://haoyuanliu.github.io/2016/04/18/Josephus/ 对,我是来骗访问量的!O(∩_∩)O~~ 约瑟夫问题(Josephus Problem)也称 ...
- LightOJ - 1179 Josephus Problem(约瑟夫环)
题目链接:https://vjudge.net/contest/28079#problem/G 题目大意:约瑟夫环问题,给你n和k(分别代表总人数和每次要数到k),求最后一个人的位置. 解题思路:因为 ...
- 谁能笑到最后,约瑟夫环-Josephus问题求解
一. 简述Josephus问题 N个人站成一环,从1号开始,用刀将环中后面一个人“消灭“”掉,之后再将刀递给下一个人,这样依次处理,最后留下一个幸存者. 二. 求解方法 1. 约瑟夫问题如果使用 ...
- 算法Sedgewick第四版-第1章基础-017一约瑟夫问题(Josephus Problem)
/************************************************************************* * * Josephus problem * * ...
- Josephus环的四种解法(约瑟夫环)
约瑟夫环 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个 ...
- Josephus problem(约瑟夫问题,丢手绢问题)
约瑟夫问题 约瑟夫环问题是一个数学应用题:已知n个人(以编号1,2,3.....,n)围坐在一张圆桌的周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列 ...
- 单向环形链表解决约瑟夫环(Josephus)问题
一.约瑟夫环问题 Josephu 问题为:设编号为1,2,- n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那 ...
- Roman Roulette(约瑟夫环模拟)
Roman Roulette Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)To ...
随机推荐
- cocopods 知识集合 及 一个 好的 国外iOS技术翻译站
http://www.exiatian.com/cocoapods%E5%AE%89%E8%A3%85%E4%BD%BF%E7%94%A8%E5%8F%8A%E9%85%8D%E7%BD%AE%E7% ...
- ajaxsearch要点1
ajaxsearch中必须将form的class定义为pagerForm,才能在foot中submit按钮得到值
- web前端基础篇⑧
1.伪类选择器 都以冒号开始.:focus 焦点的地方加样式:first-child 向元素的第一个子元素添加样式锚伪类:a:link {color:red} 未访问的链接 a:visited {co ...
- nslog一些用法
1.nslog打印方法出来 NSLog(@"%@",NSStringFromSelector(_cmd)); 2.debug模式下打印一些信息,release模式下则不打印 #if ...
- How to browse the entire documentation using XCode 5 Documentation and API Reference ?
file:///Users/yangiori/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.Ap ...
- cornerstone忽略显示.DS_Store文件
在MacOS上使用svn工具时,经常发现变化列表里出现一堆的?文件,.DS_Store,对有强迫症的人来说很郁闷.处理起来很简单,就是在svn的配置里忽略这个文件.#ue ~/.subversion/ ...
- java导出excel报错:getOutputStream() has already been called for this response
对于java导出excel报错的问题,查了很多都说是在使用完输出流以后调用以下两行代码即可 out.clear(); out = pageContext.pushBody(); 但这也许是页面上输出时 ...
- web安全之sql注入实例(5.0之前的)
web安全之sql(5.0之前)注入实例 5.0之前的数据库没有information库. 所以这里需要运用的是load_file()函数来获取信息. 1.判断是否有sql注入,用and 1=1 和 ...
- 安装配置sock5代理
环境准备及安装 yum -y install pam-devel openldap-devel cyrus-sasl-devel yum -y install openssl-devel.x86_64 ...
- latch: cache buffers chains故障处理总结(转载)
一大早就接到开发商的电话,说数据库的CPU使用率为100%,应用相应迟缓.急匆匆的赶到现场发现进行了基本的检查后发现是latch: cache buffers chains 作祟,处理过程还算顺利,当 ...