算法入门(2.约瑟夫环问题)★★★★☆

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

2.猴子选大王
一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入m、n, 输出最后那个大王的编号。

3.狼找兔子问题
一座山周围有n个洞,顺时针编号为0,1,2,3,4,…,n-1.一只狼从0号洞开始,顺时针计数,每当经过第m个洞时,就进洞找兔子.例如n=5,m=3,狼经过的洞依次为0,3,1,4,2,0.输入m,n.试问兔子有没有幸免的机会?如果有该藏在哪儿?

解题思路
以上的三种问题都是约瑟夫环问题只是叫法不同,这类问题都是可以解得:首先看一个图解(以总共10人,每数3个人就杀一个。为例)
在这里插入图片描述首先最里面的圈是人位置的编号共10个,中间那个圈是一个开关圈,最外层的圈是数数的圈,原理就是从第一个人开始循环,外层数数3个数就讲中间的开关的0置为1,然后在这个置为1相当于打开开关如图,开关打开后再在这个人后面再数3个人,再将0置为1,进行比总人数少1的次数后,所有的人的开关都被打开了,(第二层都是1)就只剩最后一人(第二次开关是0)了,然后输出这个人最里面圈的位置编号就行了。
代码实现

        function joseph(n,m){//n是总人数,m是数几个数
            if(n>1||m>=1){//总人数要大于1,数的数要大于等于1才能进入下面的循环
                var cricle = new Array(n);//创建一个n个的数组存放人的被杀情况(是0还是1)
                var num = 0;//计数器用于每次数3个人
                var count = 0;//记录杀人的次数
                for(var i=0;i<cricle.length;i++){
                    cricle[i]=0;
                }//这个for循环用于将数组中所有数置0
                while(count<n-1){//如果杀人次数少于总人数少一人接着杀
                    for(var i=0;i<cricle.length;i++){//记录人的位置
                        if(cricle[i]==0){//当判断这个位置是0时
                            num++;//计数器加1
                            if(num==m){//当计数器与规定的计数(3)相等时
                                count++;//杀的人数加1
                                cricle[i]=1;//将这个人的开关置1
                                num=0;//为下一次准备计数器清零
                            }
                            if(count==n-1){//count与总人数少1相等时(杀了总人数少1)
                                break;跳出循环
                            }
                        }
                    }
                }
            }
            for(var i=0;i<cricle.length;i++){遍历开关层
                if(cricle[i]==0){找到开关为0的人
                    console.log(i+1);输出他的位置
                }
            }
        }
        joseph(10,3);

结果
4
第4个位置的人可以活下来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值