Порядок исключения у Иосифа Флавия p‌r‌o‌b‌l‌e‌m

Задача Иосифа Флавия (или перестановка Иосифа Флавия) — теоретическая задача, связанная с определенной игрой на счет.

Люди стоят в кругу в ожидании казни. Счет начинается с первой точки круга и продолжается по кругу по часовой стрелке. После того, как определенное количество людей пропущено, казнят следующего человека. Процедура повторяется с оставшимися людьми, начиная со следующего человека, двигаясь в том же направлении и пропуская такое же количество людей, пока не останется только один человек, который будет освобожден. Например, если 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, т.е. количество людей в круге на старте. Укажите порядок исключения с учетом вышеуказанных условий и ограничений.

Проще говоря, распечатайте схему смертей без использования каких-либо структур данных, таких как массивы и связанные списки.


person user3600483    schedule 02.02.2016    source источник
comment
Почему вы не спросите об этом на math.stackexchange.com?   -  person elyashiv    schedule 02.02.2016
comment
Я голосую за то, чтобы закрыть этот вопрос как не относящийся к теме, потому что он принадлежит math.stackexchange.com.   -  person uselpa    schedule 02.02.2016
comment
Потому что мне нужно закодировать проблему на C без использования каких-либо структур данных или массивов. Поскольку обмен стеками — это платформа для вопросов, связанных с программированием, я чувствовал, что он тоже здесь. Кстати, я уже разместил вопрос на math.stackexchange.com. @усэлпа   -  person user3600483    schedule 02.02.2016
comment
Подсказка: вы можете использовать стек вызовов в качестве структуры данных.   -  person Judge Mental    schedule 02.02.2016
comment
Почти уверен, что вы получите лучший ответ на math.stackexchange.com.   -  person RBarryYoung    schedule 02.02.2016
comment
Пожалуйста, не дублируйте сообщения: math.stackexchange.com/q/1637699/147357   -  person Teepeemm    schedule 02.02.2016
comment
Я голосую за то, чтобы закрыть этот вопрос как не относящийся к теме, потому что он принадлежит math.stackexchange.com.   -  person Nico Haase    schedule 22.07.2021


Ответы (3)


Я подготовил решение после изучения 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 — общее количество людей изначально. Зацикливание этой функции на всех значениях x от 1 до n дает нам порядок исключения.

person user3600483    schedule 02.02.2016
comment
кто-нибудь может угадать временную сложность решения - person user3600483; 02.02.2016
comment
Вы спрашивали порядок ликвидации. Это дает только последний стоящий человек. - person Teepeemm; 02.02.2016
comment
замена x от 1 до n дает вам порядок исключения, для x == n это дает вам последнего человека, стоящего - person user3600483; 03.02.2016

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. Очередь заботится о сохранении новой позиции. Альтернативный способ — решить с помощью рекуррентного соотношения.

person Abhay Kumar    schedule 20.02.2020

Существует подход, использующий упорядоченный набор

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

  • Инициализируйте упорядоченный набор V и вставьте элементы в диапазоне [1, N] в V.
  • Инициализируйте переменную, скажем, pos как 0, чтобы сохранить индекс удаленного элемента.
  • Iterate until the size of V is greater than 1, and perform the following steps:
    • Store the size of the set in a variable, say X
    • Обновите значение pos до (pos + K) % X.
    • Напечатайте элемент, на который указывает pos в V, а затем сотрите его.
    • Обновите 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

person unglinh279    schedule 22.07.2021