关于约瑟夫环问题的扩展

本人已经有了一段时间的计算机学习和算法的学习经历,今天碰巧看到了当时学习链表时的一个经典题目,约瑟夫环。下面先大概讲讲题目的一个背景

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式:41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是一开始要站在什么地方才能避免自杀?

看到这里,很多人的就已经跃跃欲试了,这个简单,链表模拟 一下就写好了。  确实,很多人学链表的时候遇到的第一个问题可能就是约瑟夫环了,这里提供一下链表的代码。

public class csdn_24 {
    //设计一个结点类, 因为会设计到环形链表所以自己设计是最好的
    private static class Node{  
        int value;  
        Node next;
        public Node(int value){
            this.value = value;
        }
    }
    // m 个人 m 个人会噶
    public int circle(int n, int m) {
        Node head = new Node(0);
        Node temp = head;
        for(int i = 1 ; i < n ; i++){
            temp.next = new Node(i);
            temp = temp.next;
        }
        temp.next = head;
        int index = 0;
        while(head.next != head){
            if(index == m-2){
                head.next = head.next.next;
                index = 0;
            }
            else{
                index++;
            }
            head = head.next;
        }
        return head.value;
    }
}

代码比较简单也比较基础,就不多说明了。

分析一下不能发现算法的时间复杂度 高达O(nm) , 当 n, m 非常大的时候,性能其实是很差的。

这里我们重点说一下用数学如何对这个问题进行一个优化。 

这里先给出公式

f(N,M)=(f(N−1,M)+M)%N

这里的n表示有n个人 报道m的人就噶。

package org.czl;

public class csdn_24P {
    int circle(int n,int m)
    {
        int p=0;
        for(int i=2;i<=n;i++)
        {
            p=(p+m)%i;
        }
        return p+1;
    }
}

这里我们来详细解释一下上述代码和公式

公式简单点来说 就是描述幸存者下标的位置。

这里我们不妨假设一个问题, 就是此时场上有 m 个人 第 n 个人被删除 我们如果知道了在这种 m和n的情况下, 最后活下来的人是第 y 号, 那我们想一想 第一次删除的时候 把第n个人删了 ,我们下一个开头就是n + 1个人 总人数就变为了 m - 1. 如果我们此时在假设m - 1的下标为0 那最后活下的人就是y + n 号了。 就是把每一个新的开始看做开头,最后活下来的人也会相对应的往后延迟多少个位置, 但是相对位置始终是不变的。

这个公式就能很好的解释了 f(N,M)=(f(N−1,M)+M)%N。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值