zoukankan      html  css  js  c++  java
  • 如何利用约瑟夫环来保护你与你的朋友

    题目描述:

    据说著名犹太历史学家 Josephus(约瑟夫)有过以下的故事:在罗马人占领乔塔帕特后, 39 个犹太人与 Josephus 及他的朋友躲到一个洞中,39 个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41 个人排成一个圆圈,由第 1 个人开始报数,报数每报到第 3 个人该人就必须自杀,然后再由下一个人从 1 开始重新报数,直到所有人都自杀身亡为止。
    然而 Josephus 和他的朋友并不想遵从,Josephus 要他的朋友先假装遵从,他将朋友与自己安排在第 16 个与第 31 个位置,于是逃过了这场死亡游戏。
    约瑟夫问题可用代数分析来求解,假设现在你与 m 个朋友不幸参与了这个游戏,你要如何保护你与你的朋友?

    分析与解答:

    实际上只要画两个圆圈就可以让自己与朋友免于死亡游戏,这两个圆圈中内圈是排列顺序,而外圈是自杀顺序,如下图所示。

    使用程序来求解的话,只要将阵列当作环状来处理,在阵列中由计数 1 开始,每三个数得到一个计数,直到计数到 41 为止;然后将阵列由索引 1 开始列出,就可以得知每个位置的自杀顺序,这就是约瑟夫排列。41 个人报数的约瑟夫排列如下所示(第一个开始对应每个人的站位):
    14 36 1 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23
    由上述排列可知,最后一个自杀的是在第 31 个位置的人,而倒数第二个自杀的要排在第 16 个位置,之前的人都死光了,所以他们也就不知道约瑟夫与他的朋友有没有遵守游戏规则了。
    实现代码如下:

    define('N', 41);//参与人数
    define("M", 3);//每逢3自杀
    $man = array(0);
    $count = 1;
    $i = 0;
    $pos = -1;
    $alive = 2;//想要救的三个人
    while ($count <= N) {
        do {
            $pos = ($pos + 1) % N;
            if (@$man[$pos] == 0)
                $i++;
            if ($i == M) {
                $i = 0;
                break;
            }
        } while (1);
        $man[$pos] = $count;
        $count++;
    }
    
    arsort($man);
    
    $arr = array_slice($man, 0, $alive, true);
    
    for ($i = 0; $i < N; $i++) {
        echo "" . $man[$i] . '-';
    }
    

    程序的运行结果为

    14-36-1-38-15-2-24-30-3-16-34-4-25-17-5-40-31-6-18-26-7-37-19-8-35-27-9-20-32-10-41-21-11-28-39-12-22-33-13-29-23
    
  • 相关阅读:
    Java实现 LeetCode 371 两整数之和
    Java实现 LeetCode 371 两整数之和
    Java实现 LeetCode 371 两整数之和
    Java实现 LeetCode 1013 将数组分成和相等的三个部分
    Java实现 LeetCode 1013 将数组分成和相等的三个部分
    Java实现 LeetCode 1013 将数组分成和相等的三个部分
    Java实现蓝桥杯VIP算法训练 纪念品分组
    Java实现蓝桥杯VIP算法训练 纪念品分组
    linux下syscall函数,SYS_gettid,SYS_tgkill
    可变参数宏__VA_ARGS__和...
  • 原文地址:https://www.cnblogs.com/hardy-wang/p/12968655.html
Copyright © 2011-2022 走看看