算法习题18:约瑟夫环(n个数字(0,1,…,n-1)形成一个圆圈)
2013-10-17 15:47
267 查看
题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,
每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字。
求出在这个圆圈中剩下的最后一个数字。
--------------------------------
约瑟夫环是一个数学的应用问题:已知n小伙伴(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人只剩最后一个小伙伴。。找出这个小伙伴把!
(1)方法一
当然是直接模拟这个过程:可以利用一个链表(环形)来模拟,也可以直接用数组,记得%n就好了
(2)约瑟夫算法
约瑟夫这个算法确实很巧妙!
看了好几篇文章,都觉得抄得太high了,着实让智商不够的我纠结了一阵子。。
其实这里就是一个回溯的感觉
假设我们现在要先找到n个元素里第m个 那么就是a[m-1]这个元素被删除了,然后数组变换如下:
0 1 ... m-2 m-1 m ... n-1
0 1 ... m-2 m m+1 ... n -1
我们接下来是从arr[m] 这个元素开始了,如果我们重新把这个新数组看成一个新数组,那么可以表示如下
m m+1 ... n-1 0 1 ... m-2 数组一
如果依然从0开始标记:(对应上面这个数组)
0 1 .... n-m-1 n-m n-m+1 n-2 数组二
我们发现,如果这时候数组二和数组一是一一对应的,如例如数组二的 第n-m+1元素就是数组一的 1元素所以如果数组二的元素位置记为x,在数组一的元素位置记为x'
则有数组二-----》数组一关系 x' = (x+m)%n
那同理,数组三 ---->数组二 就有 x' = (x+m)%(n-1)
所以,如果我们知道了最后一个数组(也就是只剩最后一个元素,他的位置标记当然是0 了 ,一个元素的数组下标就是0),就可以推出剩下两个元素里该元素的位置。。。。以此类推,就可以得到最后剩下那个元素在初始数组里的位置了。。。
确实不好解释,大家想想,就是假设我知道了,最后剩下的那个元素,也就是最后剩下的数组,这个数组我们重新排序了,那这个元素在这个数组的下标肯定是0,好了,我们可以通过这个数组推出该元素在上一个数组(含有两个元素)的坐标,然后再推出上上个数组里的坐标。。。。。
_______________________|
0 if i==1 |
f(i) ={ |
(f(i-1)+m)%i if i>1 |
----------------------------------------|
每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字。
求出在这个圆圈中剩下的最后一个数字。
--------------------------------
约瑟夫环是一个数学的应用问题:已知n小伙伴(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人只剩最后一个小伙伴。。找出这个小伙伴把!
(1)方法一
当然是直接模拟这个过程:可以利用一个链表(环形)来模拟,也可以直接用数组,记得%n就好了
//============================================================================ // Name : YSFCircle.cpp // Author : YLF // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> using namespace std; void Solution1(int *arr, int length, int m); int main() { int arr[10] = {0,1,2,3,4,5,6,7,8,9}; int m = 5; Solution1(arr,10,m); return 0; } /* * simulate the process */ void Solution1(int *arr, int length, int m){ int i = 0; int index = length; int mIndex = m; while(index>1){ mIndex = m; while(mIndex > 0){ if(arr[i] != -1){ mIndex--; if(mIndex == 0) arr[i] = -1; } i = (i+1)%length; } index--; } for(i=0;i<length;i++) if(arr[i] != -1) cout<<arr[i]; }
(2)约瑟夫算法
约瑟夫这个算法确实很巧妙!
看了好几篇文章,都觉得抄得太high了,着实让智商不够的我纠结了一阵子。。
其实这里就是一个回溯的感觉
假设我们现在要先找到n个元素里第m个 那么就是a[m-1]这个元素被删除了,然后数组变换如下:
0 1 ... m-2 m-1 m ... n-1
0 1 ... m-2 m m+1 ... n -1
我们接下来是从arr[m] 这个元素开始了,如果我们重新把这个新数组看成一个新数组,那么可以表示如下
m m+1 ... n-1 0 1 ... m-2 数组一
如果依然从0开始标记:(对应上面这个数组)
0 1 .... n-m-1 n-m n-m+1 n-2 数组二
我们发现,如果这时候数组二和数组一是一一对应的,如例如数组二的 第n-m+1元素就是数组一的 1元素所以如果数组二的元素位置记为x,在数组一的元素位置记为x'
则有数组二-----》数组一关系 x' = (x+m)%n
那同理,数组三 ---->数组二 就有 x' = (x+m)%(n-1)
所以,如果我们知道了最后一个数组(也就是只剩最后一个元素,他的位置标记当然是0 了 ,一个元素的数组下标就是0),就可以推出剩下两个元素里该元素的位置。。。。以此类推,就可以得到最后剩下那个元素在初始数组里的位置了。。。
确实不好解释,大家想想,就是假设我知道了,最后剩下的那个元素,也就是最后剩下的数组,这个数组我们重新排序了,那这个元素在这个数组的下标肯定是0,好了,我们可以通过这个数组推出该元素在上一个数组(含有两个元素)的坐标,然后再推出上上个数组里的坐标。。。。。
_______________________|
0 if i==1 |
f(i) ={ |
(f(i-1)+m)%i if i>1 |
----------------------------------------|
/* * using YSF Algorithm */ void Solution2(int *arr, int length, int m){ int last = YSF(length,m); cout<<arr[last]; } int YSF(int i , int m){ if(i == 1) return 0; return (YSF(i-1, m)+m)%i; }
相关文章推荐
- 每天学习一算法系列(18)(n 个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m 个数字)
- [约瑟夫环]n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始... ...
- [约瑟夫环]n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始... ...
- [约瑟夫环]n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始... ...
- n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始(18)
- 微软面试100题之18题:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始... ...
- 16. 微软面试题:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始
- 第18 题:题目:n 个数字(0,1,…,n-1)形成一个圆圈,从数字0 开始,
- 第18 题: 题目:n 个数字(0,1,…,n-1)形成一个圆圈,从数字0 开始每次从这个圆圈中删除第m 个数字(第一个为当前数字本身,第二个为当前数字的下一个数 字)。
- 第18题: 题目:n个数字(0,1,„,n-1)形成一个圆圈,从数字0开始, 每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。 当一个数字删除后,从被删除数字的下
- 【编程题目】n 个数字(0,1,…,n-1)形成一个圆圈,从数字 0 开始
- n 个数字(0,1,…,n-1)形成一个圆圈,从数字0 开始,每次从这个圆圈中删除第m 个数字
- 每天学习一点编程(7)(n 个数字(0,1,…,n-1)形成一个圆圈,从数字0 开始,每次从这个圆圈中删除第m 个数字)
- n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始
- 【微软100题】n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始, 每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。 当一个数字删除后,从被删除数
- n个数字形成一个圆圈,隔m个数字删除一个的问题
- n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。当一个数字删除后,从被删除数字的下一个继续删除第m个数字
- <仅是自己做笔记。。。系列-10>n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。
- 18.n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始, 每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。 当一个数字删除后,从被删除数字的下一个继续删除第m个数字。 求出在这个圆圈中剩下的最后一个数字。
- 算法习题14:输入一个已经按升序排序过的数组和一个数字