目录
问题概述:
问题解析:
图文示意:
处决开始:
第一轮结束:
第二轮结束:
最后一轮:
寻找规律:
最终思路:
具体代码:
总结:
问题概述:
在犹太战争期间,约瑟夫与多名犹太士兵被困在一个洞穴中,面临被罗马军队俘虏的危险。为了避免成为罗马人的奴隶,士兵们决定由顺时针从第一个人开始处决他旁边的人,下一个人再处决他旁边的人,直到剩最后一个人自尽。但是约瑟夫想向罗马人投降,但是他也不敢暴露自己的想法,最后约瑟夫通过数学计算,找到了一个可以让他成为最后幸存者的位置,从而避免了死亡的命运。那么假设一共有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的值过大,为了拓展知识面,大家可以使用数组法,递归法,链表法等等。
后来这种问题又演化成各种题目,例如循环报数,所代表的数据结构是队列。
(时间仓促,如有码字错误,请谅解。)