约瑟夫环算法研究

今天在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。据此可写出迭代或递推算法。
以下是迭代算法:
 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;
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值