📜  约瑟夫斯问题|集合1(AO(n)解)

📅  最后修改于: 2021-04-29 15:23:06             🧑  作者: Mango

在计算机科学和数学中,约瑟夫斯问题(或约瑟夫斯置换)是一个理论问题。以下是问题陈述:
n人围成一圈等待执行。计数从圆的某个点开始,然后沿固定的方向围绕圆进行。在每个步骤中,将跳过一定数量的人员,然后执行下一个人员。消灭围绕圈进行(随着被处决者的撤离,圈变得越来越小),直到只有最后一个剩下的人被赋予了自由。给定总人数n和数字k,表示跳过k-1个人,第k个人被圈杀。我们的任务是选择第一个圆圈中的位置,以便您成为最后一个剩下的人,从而生存下来。
例如,如果n = 5且k = 2,则安全位置为3。首先,杀死位置2的人员,然后杀死位置4的人员,然后杀死位置1的人员。最终,位置5的人被杀死。因此,位置3的人幸存下来。
如果n = 7且k = 3,则安全位置为4。位置3、6、2、7、5、1的人员被依次杀害,位置4的人员幸存。

该问题具有以下递归结构。

josephus(n, k) = (josephus(n - 1, k) + k-1) % n + 1
  josephus(1, k) = 1

第一个人(从第k个开始)被杀死后,剩下n-1个人。因此,我们将josephus(n – 1,k)称为n-1人。但是josephus(n – 1,k)返回的位置将考虑从k%n + 1开始的位置。因此,我们必须对josephus(n – 1,k)返回的位置进行调整。
以下是约瑟夫斯问题的简单递归实现。该实现仅遵循上述递归结构。

C++
#include 
using namespace std;
 
int josephus(int n, int k)
{
    if (n == 1)
        return 1;
    else
        /* The position returned by josephus(n - 1, k)
        is adjusted because the recursive call
        josephus(n - 1, k) considers the
        original position k % n + 1 as position 1 */
        return (josephus(n - 1, k) + k-1) % n + 1;
}
 
// Driver Program to test above function
int main()
{
    int n = 14;
    int k = 2;
    cout << "The chosen place is " << josephus(n, k);
    return 0;
}
 
// This code is contributed by shubhamsingh10


C
#include 
 
int josephus(int n, int k)
{
  if (n == 1)
    return 1;
  else
    /* The position returned by josephus(n - 1, k) is adjusted because the
       recursive call josephus(n - 1, k) considers the original position
       k%n + 1 as position 1 */
    return (josephus(n - 1, k) + k-1) % n + 1;
}
 
// Driver Program to test above function
int main()
{
  int n = 14;
  int k = 2;
  printf("The chosen place is %d", josephus(n, k));
  return 0;
}


Java
// Java code for Josephus Problem
import java.io.*;
 
class GFG {
 
static int josephus(int n, int k)
{
if (n == 1)
    return 1;
else
    /* The position returned by josephus(n - 1, k)
    is adjusted because the recursive call
    josephus(n - 1, k) considers the original
    position k%n + 1 as position 1 */
    return (josephus(n - 1, k) + k-1) % n + 1;
}
 
// Driver Program to test above function
public static void main(String[] args)
{
int n = 14;
int k = 2;
System.out.println("The chosen place is " + josephus(n, k));
}
}
 
// This code is contributed by Prerna Saini


Python3
# Python code for Josephus Problem
 
def josephus(n, k):
 
      if (n == 1):
          return 1
      else:
     
     
          # The position returned by
          # josephus(n - 1, k) is adjusted
          # because the recursive call
          # josephus(n - 1, k) considers
          # the original position
          # k%n + 1 as position 1
          return (josephus(n - 1, k) + k-1) % n + 1
 
# Driver Program to test above function
 
n = 14
k = 2
 
print("The chosen place is ", josephus(n, k))
 
# This code is contributed by
# Sumit Sadhakar


C#
// C# code for Josephus Problem
using System;
 
class GFG {
     
    static int josephus(int n, int k)
    {
        if (n == 1)
            return 1;
        else
            /* The position returned
            by josephus(n - 1, k) is
            adjusted because the
            recursive call josephus(n
            - 1, k) considers the
            original position k%n + 1
            as position 1 */
            return (josephus(n - 1, k)
                       + k-1) % n + 1;
    }
     
    // Driver Program to test above
    // function
    public static void Main()
    {
        int n = 14;
        int k = 2;
        Console.WriteLine("The chosen "
        + "place is " + josephus(n, k));
    }
}
 
// This code is contributed by anuj_67.


PHP


Javascript


C++
#include 
using namespace std;
 
int Josephus(int, int);
 
int main()
{
    int n, k;
    cin >> n >> k;
    cout << Josephus(n, k);
    return 0;
}
 
int Josephus(int n, int k)
{
    k--;
    int arr[n];
    for (int i = 0; i < n; i++)
    {
        arr[i] = 1; // Makes all the 'n' people alive by assigning them value = 1
    }
    int cnt = 0, cut = 0,
        num = 1; // Cut = 0 gives the sword to 1st person.
    while (
        cnt < (n - 1)) // Loop continues till n-1 person dies.
    {
        while (num <= k) // Checks next (kth) alive persons.
        {
            cut++;
            cut = cut % n; // Checks and resolves overflow of Index.
            if (arr[cut] == 1)
            {
                num++; // Updates the number of persons alive.
            }
        }
        num = 1;      // refreshes value to 1 for next use.
        arr[cut] = 0; // Kills the person at postion of 'cut'
        cnt++;        // Updates the no. of killed persons.
        cut++;
        cut = cut % n;        // Checks and resolves overflow of Index.
        while (arr[cut] == 0) // Checks the next alive person the sword is to be given.
        {
            cut++;
            cut = cut % n; // Checks and resolves overflow of Index.
        }
    }
    return cut + 1; // Output is the position of the last man alive(Index + 1);
}
 
/********************THIS CODE IS PRESENTED BY SHISHANK RAWAT**************************/


输出:

The chosen place is 13

时间复杂度: O(n)

使用列表的另一种方法:

一种简单的方法是创建一个列表,并在其中添加从1到n的所有值。创建一个递归函数,该函数将list,start(开始计数的位置)和k(要跳过的人数)作为参数。如果列表的大小为1,即仅剩一个人,则返回此位置。否则,从起始位置开始按顺时针方向对k个人进行计数,然后移至第k位。现在,位于第k个位置的人员将被移走,并且现在将从该位置开始计数。这个过程一直持续到只剩下一个人为止。

pseudo-code :

Josephus( list , start , k){
   if list.size = 1
       return list[0]
   start = (start + k) % list.size
   list.remove( start )
   return Josephus( list, start, k)
}

范例

Input : n = 5,  k = 2
output : 3

解释 :

将列表中从1到n的所有值相加。我们将以start = 0和k = 1(0索引)调用递归函数

现在,位于1索引处的元素(2号人员)将被杀死。并将其从列表中删除。新的计数将从1索引开始,1索引处的人员被杀死,因此现在2索引处的人员(第3个人)变为1索引,并且从现在开始计数。

现在我们有4个人,从1索引(3号人)开始计数,处于kth(2索引)位置的人将被杀死。

2点索引的人(4号人)被杀,所以现在我们剩下3个人,而3点索引的人(5号人)转移到2点索引。从这里开始计数。

0索引处的人被杀,现在圈子里还剩下两个人。 1索引处的人员转移到0索引处,即人数3。

完成最后的计数,杀死处于1索引的人员,只有剩下的人员位于位置3。

这是C++中约瑟夫斯(Josephus)问题的解决方案。

对于n = 47和k = 5。

C++

#include 
using namespace std;
 
int Josephus(int, int);
 
int main()
{
    int n, k;
    cin >> n >> k;
    cout << Josephus(n, k);
    return 0;
}
 
int Josephus(int n, int k)
{
    k--;
    int arr[n];
    for (int i = 0; i < n; i++)
    {
        arr[i] = 1; // Makes all the 'n' people alive by assigning them value = 1
    }
    int cnt = 0, cut = 0,
        num = 1; // Cut = 0 gives the sword to 1st person.
    while (
        cnt < (n - 1)) // Loop continues till n-1 person dies.
    {
        while (num <= k) // Checks next (kth) alive persons.
        {
            cut++;
            cut = cut % n; // Checks and resolves overflow of Index.
            if (arr[cut] == 1)
            {
                num++; // Updates the number of persons alive.
            }
        }
        num = 1;      // refreshes value to 1 for next use.
        arr[cut] = 0; // Kills the person at postion of 'cut'
        cnt++;        // Updates the no. of killed persons.
        cut++;
        cut = cut % n;        // Checks and resolves overflow of Index.
        while (arr[cut] == 0) // Checks the next alive person the sword is to be given.
        {
            cut++;
            cut = cut % n; // Checks and resolves overflow of Index.
        }
    }
    return cut + 1; // Output is the position of the last man alive(Index + 1);
}
 
/********************THIS CODE IS PRESENTED BY SHISHANK RAWAT**************************/

如果你们喜欢它,请发表评论并帮助我做进一步的改进。

输出
The safe position : 4