趣味算法------约瑟夫环


目录

问题概述:

问题解析:

图文示意:

处决开始:

 

第一轮结束:

 第二轮结束:

最后一轮:

寻找规律:

最终思路:

具体代码:

总结:


问题概述:

        在犹太战争期间,约瑟夫与多名犹太士兵被困在一个洞穴中,面临被罗马军队俘虏的危险。为了避免成为罗马人的奴隶,士兵们决定由顺时针从第一个人开始处决他旁边的人,下一个人再处决他旁边的人,直到剩最后一个人自尽。但是约瑟夫想向罗马人投降,但是他也不敢暴露自己的想法,最后约瑟夫通过数学计算,找到了一个可以让他成为最后幸存者的位置,从而避免了死亡的命运。那么假设一共有n个人,约瑟夫应该站在第几个人的位置才能活到最后。


问题解析:

        假设现在有 8 个人,编号分别为1~8现在由第一个位置上人处决第二个位置上的人,再由第三个人处决第四个人,第一圈后还剩 1 3 5 7。然后继续 1 处决 3, 5 处决 7,还剩 1 , 5,最后 1处决 5。1活到最后。

图文示意:

处决开始:

 

第一轮结束:

1 处决 2, 3处决4,5处决6,7处决8。

 第二轮结束:

        1处决3,5处决7。

最后一轮:

        1处决5,仅剩1号位一个人。所以当人数为8人时,安全位为第一人的位置。

寻找规律:

        通过上文中的打表方式我们找出当人数为1~10时,最后存活的位置。

        这时候我们发现当士兵人数为2的幂次方时,第一个位置的人就能活到最后。实际上我们也能轻松的推导出来,假设士兵人数是2的幂次方时,每一轮都要处决一半的人,最后被处决的一定是环内最后一个人,这样下一轮第一个进行处决同伴的人一定还是第一号位置,到了最后活着的人一定还是一号位的人。

最终思路:

        假设士兵人数不为2的幂次方呢?我们要知道,士兵在互相处决的过程中,人数是一个一个 递减的,所以无论有多少人,在处决的过程中,人数一定会变成2的幂次方,然后由下一个操刀手成为一号位,他将活到最后。

        假设一共有9个人,刚开始 1处决 2,还剩8个人,8个人为2的幂次方,下一个操刀手3号位相当于活到最后的“一号位”。

        假设一共有10个人,刚开始 1处决 2,还剩9个人,然后 3 处决 4,还剩8个人,8个人为2的幂次方,下一个操刀手5号位相当于活到最后的“一号位”。

        所以当人数为 n 时,我们要找到最大不超过 n 的 2 的幂次方,然后让 n 减去该2的幂次方,得到到这个安全位置一共处决了 X 人,因为每处决一个人证明在这之前一定还有一个操刀手,安全位之前一共有 2*X 个人,最后得到安全位的位置为  2*X+1。

具体代码:

#include <stdio.h>
#include<math.h>
int main()
{
    int n;
    scanf("%d", &n);
    int num = 1;
    while (pow(2, num) <= n)//寻找刚好大于n的 2 的幂次方。
        num++;
    
    int X = n-pow(2, num - 1);//处决人数,这里num要减1。

    printf("%d", 2 * X + 1);//打印安全位置。
   
}

总结:

        该方法适用于当n的值过大,为了拓展知识面,大家可以使用数组法,递归法,链表法等等。

后来这种问题又演化成各种题目,例如循环报数,所代表的数据结构是队列。

(时间仓促,如有码字错误,请谅解。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值