约瑟夫环算法研究
2014-11-27 17:48
260 查看
今天在CSDN论坛上看到这个问题:
500个小孩围成一圈,从第一个开始报数:1,2,3,1,2,3,1,2,3,……每次报3的小孩退出
问最后剩下的那个小孩,在以前500人里是第几个???
用LinkedList模拟报数和删除行为,算出最终结果是436。但是当总人数特别大时,此算法效率就非常低。
import java.util.*;
class Test{
public static void main(String[] args){
List<Integer> list = new LinkedList<Integer>();
for(int i = 1; i <= 500; i ++){
list.add(i);
}
int index = 2;//第一个报到3的小孩,索引是2
while(list.size()> 1){
list.remove(index);
index = index - 1;//移除该位元素后,下次需要从该位开始遍历,故减1
index = (index +3)%list.size();
}
System.out.println(list.get(0));
}
}
回帖里有人提及这是约瑟夫问题,于是百度了一下,找到一般性的问题描述:
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列,求最后一个出列人的编号。
在写算法思路之前,先记录自己做题时走过的弯路:
先假设m,n均为正整数,m%n和(m-1)%n+1,这两个式子在大部分情况下是等效的,但是当m为n的倍数时,前一个式子的值是0,后一个式子的值是n。
下面讲此题思路:
题中第k人开始报1,则第(k+m-2)%n+1人报到m出列,接下来第(k+m-1)%n+1继续开始报1。一共n-1个数次序为:
(k+m-1)%n+1, (k+m)%n+1, (k+m+1)%n+1……(k+m-3)%n+1 ①
调整次序,使第一个数的次序仍为k:
k, k+1, k+2,……k-2 ②
可见问题转化成为n-1人时的约瑟夫环。假设此时最后一个出列的人的编号为f(n-1),那么将它作一个逆向变换就可以得到n人约瑟夫环的解:
f(n) = [f(n-1)+m-1]%n+1
由于n是题设中的最大人数,将它换成其他变量以免混淆:
f(i) = [f(i-1)+m-1]%i+1
由于始终是第k人开始报1,那么当总人数为1时,f(1)=k。据此可写出迭代或递推算法。
以下是迭代算法:
500个小孩围成一圈,从第一个开始报数:1,2,3,1,2,3,1,2,3,……每次报3的小孩退出
问最后剩下的那个小孩,在以前500人里是第几个???
用LinkedList模拟报数和删除行为,算出最终结果是436。但是当总人数特别大时,此算法效率就非常低。
import java.util.*;
class Test{
public static void main(String[] args){
List<Integer> list = new LinkedList<Integer>();
for(int i = 1; i <= 500; i ++){
list.add(i);
}
int index = 2;//第一个报到3的小孩,索引是2
while(list.size()> 1){
list.remove(index);
index = index - 1;//移除该位元素后,下次需要从该位开始遍历,故减1
index = (index +3)%list.size();
}
System.out.println(list.get(0));
}
}
回帖里有人提及这是约瑟夫问题,于是百度了一下,找到一般性的问题描述:
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列,求最后一个出列人的编号。
在写算法思路之前,先记录自己做题时走过的弯路:
先假设m,n均为正整数,m%n和(m-1)%n+1,这两个式子在大部分情况下是等效的,但是当m为n的倍数时,前一个式子的值是0,后一个式子的值是n。
下面讲此题思路:
题中第k人开始报1,则第(k+m-2)%n+1人报到m出列,接下来第(k+m-1)%n+1继续开始报1。一共n-1个数次序为:
(k+m-1)%n+1, (k+m)%n+1, (k+m+1)%n+1……(k+m-3)%n+1 ①
调整次序,使第一个数的次序仍为k:
k, k+1, k+2,……k-2 ②
可见问题转化成为n-1人时的约瑟夫环。假设此时最后一个出列的人的编号为f(n-1),那么将它作一个逆向变换就可以得到n人约瑟夫环的解:
f(n) = [f(n-1)+m-1]%n+1
由于n是题设中的最大人数,将它换成其他变量以免混淆:
f(i) = [f(i-1)+m-1]%i+1
由于始终是第k人开始报1,那么当总人数为1时,f(1)=k。据此可写出迭代或递推算法。
以下是迭代算法:
public int fun(int n, int m, int k){ int result = k;//当总人数为1时, for(int i = 2; i <= n; i++){ result = (result + m - 1) % i + 1; } return result; }
相关文章推荐
- 约瑟夫环算法研究
- 图像匹配的若干算法的研究
- 经典算法研究系列:六、教你初步了解KMP算法、updated
- 算法面试题总结---以后留着慢慢研究
- 传输数据校验算法研究
- 算法研究之开灯问题
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大系列集锦
- 【深度干货】2017年深度学习优化算法研究亮点最新综述(附slide下载)
- spark机器学习算法研究和源码分析
- 五子棋算法研究
- 关于卡马克算法和系统函数库方法快速开平方根快慢的研究
- 经典算法研究系列:四、教你通透彻底理解:BFS和DFS优先搜索算法
- 基于纹理的图像检索算法研究
- 基于贝叶斯决策的彩色图像中皮肤区域检测算法研究与实现
- DOTA2比赛赛前预测算法的研究(一)--介绍
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大系列集锦
- 对大量转载贴识别算法的研究
- 经典算法研究系列:七、深入浅出遗传算法,透析GA本质
- 双目视觉算法研究(二)相机模型和直接线性法(DLT)
- 叠加分析算法对比研究分析之二