约瑟夫环问题的思路与实现

一、约瑟夫环是什么?

约瑟夫环是一个古老的问题,起源于一个犹太故事。
我们可以将它简化为一个围圈丢手绢的问题,有n个同学的同学按照编号1-n依次围成一个圈在玩手绢游戏,有一个裁判在圈内正对1号同学,每数到第m个同学就淘汰该同学,最后剩下的一个同学为游戏获胜者。
例如:5个同学游戏,m为2,首先淘汰2号,接着淘汰4号,1号。此时,只剩余3号同学,他获得该游戏的胜利!

二、三个方法

1.模拟法

模拟法顾名思义就是模拟游戏的过程来实现,时间复杂度往往较高,不过有利于我们来理解(主要是想不到别的55),特点就是一步一步来进行,比较形象。时间复杂度: f ( n ) = O ( n m ) f(n)=O(nm) f(n)=O(nm)

代码如下:

    public static void FindWinner(int n,int k){
        boolean[] visit=new boolean[n+1];
        int count=0;				
        int pos=1;						//裁判初始时在1号小伙伴面前
        int sum=n;
        while(sum>1){
            if(!visit[pos]){			//如果玩家在圈内
                count++;				//计数
                if(count%k==0){			//计数达到要求
                    visit[pos]=true;	//淘汰编号为pos的玩家
                    sum--;				//剩余多少人?
                    System.out.println("小伙伴"+pos+"离开!");
                }
            }
            pos=pos%n+1;				//类似于循环队列的知识
        }
        for(int i=1;i<n+1;i++){
            if(!visit[i]){
                System.out.println("小伙伴"+i+"获胜!");
                break;
            }
        }
    }

2.递归算法

现在只要求我们找到最终的胜利者,我们是否还需要上述操作呢。我们回到题目,n个同学玩游戏,一共淘汰多少轮呢?答案是n-1轮。当我们进行完第一轮的淘汰,编号为(m-1)%n+1的同学被淘汰了 。剩下的n-1个人,组成了一个新环。给他们重新编号(被淘汰的同学的后一位为1号)。如果我们找到最后,找到了一个胜者。这个胜者不仅是环为n-1时的胜者,也是n时的胜者,只是他的编号变了,因此我们做的事情就是从1个人为环开始,建立两轮编号之间的联系
f ( n ) = ( m + f ( n − 1 ) − 1 ) m o d n + 1 f(n)=(m+f(n-1)-1) mod n+1 fn=(m+f(n1)1)modn+1

代码如下:

    public static int Winner(int n,int m){
        if(n==1)
            return 1;
        return (m+Winner(n-1,m)-1)%n+1;
    }

3.递推算法

看懂了递归,递推公式也就出来了。

    public static int Winner(int n,int m){
        int ans=1;
        for(int i=2;i<=n;i++){
            ans=(m+ans-1)%i+1;
        }
        return ans;
    }

总结

约瑟夫环的问题并不难,但是我们在遇到这些数学问题时还是要先找规律,有的模拟起来可能非常困难(比如蚂蚁爬杆问题)。以上就是今天的分享。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

登sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值