约瑟夫斯问题中的消除顺序

时间:2016-02-02 18:08:59

标签: algorithm math recursion josephus

Josephus Problem(或Josephus permutation)是一个与某个计数游戏相关的理论问题。

  

人们站在一个等待被处决的圈子里。数数   从圆圈的第一个点开始,围绕圆圈前进   顺时针方向。在指定数量的人之后   跳过,下一个人被执行。重复该过程   剩下的人,从下一个人开始,也是一样的   方向和跳过相同数量的人,直到只有一个   人仍然存在,并被释放。例如,如果n = 10那么顺序为   消除是2,4,6,8,10,3,7,1,9和5

The problem is, without simulation of the above game, try to find out the order of 
elimination through means of mathematical formula or a mathematical pattern.

最初我们被给予n,即圈子中的人数。给出消除顺序,记住上述条件和约束。

简单来说,在不使用数组和链接列表等任何数据结构的情况下打印死亡模式。

3 个答案:

答案 0 :(得分:1)

我在研究http://www.cs.man.ac.uk/~shamsbaa/Josephus.pdf后准备了解决方案。 上面的pdf中提到了这种递归。

int last_man(int n,int x)
{
    if(n==1 && x==1)
        return 1;
    else if(n>1 && x==1)
        return 2;
    else if(last_man(n-1,x-1)==n-1)
        return 1;
    else
        return last_man(n-1,x-1)+2;
}

X表示死亡的第x个人,n是最初的总人数。 将此函数循环到从1到n的x的所有值,为我们提供了elemination的顺序。

答案 1 :(得分:1)

有一种使用有序集的方法

(https://www.geeksforgeeks.org/ordered-set-gnu-c-pbds/):

  • 初始化一个有序集合 V,并将[1, N]范围内的元素插入到V中。
  • 初始化一个变量,比如 pos0,以存储被移除元素的索引。
  • 迭代直到V的大小大于1,执行以下步骤:
    • 将集合的大小存储在一个变量中,比如 X
    • pos 的值更新为 (pos + K) % X
    • V中打印pos指向的元素,然后将其擦除
    • pos 更新为 pos%V.size()
  • 打印存储在集合 V 开头的最后一个元素

代码如下:

#include <iostream>
using namespace std;

// Header files, namespaces to use
// ordered set
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ordered_set                          \
    tree<int, null_type, less<int>, rb_tree_tag, \
        tree_order_statistics_node_update>

// Function to find the person who
// will get killed in the i'th step
void orderOfExecution(int N, int K)
{

    // Create an ordered set
    ordered_set V;

    // Push elements in the range
    // [1, N] in the set
    for (int i = 1; i <= N; ++i)
        V.insert(i);

    // Stores the position to be removed
    int pos = 0;

    // Iterate until the size of the set
    // is greater than 1
    while (V.size() > 1) {

        // Update the position
        pos = (pos + K) % (int)V.size();

        // Print the removed element
        cout << *(V.find_by_order(pos)) << ' ';

        // Erase it from the ordered set
        V.erase(*(V.find_by_order(pos)));

        // Update position
        pos %= (int)V.size();
    }

    // Print the first element of the set
    cout << *(V.find_by_order(0));
}

int main()
{
    int N = 5, K = 2;

    // Function Call
    orderOfExecution(N, K);

    return 0;
}

时间复杂度:O(N * log(N))

为了更好地理解,我建议您观看此视频:

https://youtu.be/KnsDFCcBJbY

答案 2 :(得分:0)

function josIterative(n, k) {
let queue = [];
for (let i = 1; i <= n; i++) queue.push(i);

let deathOrder = [];

while (queue.length !== 1) {
    for (let skip = 1; skip < k; skip++) queue.push(queue.shift());
    deathOrder.push(queue.shift());
}

console.log("Death order is " + deathOrder.join(" "));
return queue[0]; //survivor
}

console.log(josIterative(7, 3) + " is survivor");

该程序用javascript es6编写。 队列要注意保持新位置 另一种方法是使用递归关系来解决