问题
这个问题以与罗马人作战的犹太历史学家弗拉维乌斯·约瑟夫斯(Flavius Josephus)的名字命名。根据约瑟夫斯的说法,他和他的犹太士兵在一个山洞里被罗马人围困和包围,他们在投降和俘获中选择了谋杀和自杀。他们决定将所有士兵围成一圈,从坐在第一个位置的士兵开始,每个士兵将按顺序杀害该士兵。因此,如果有5名士兵围成一个圈,位置编号分别为1、2、3、4、5。士兵1杀死2,然后3杀死4,然后5杀死1,然后3杀死5,因为3是唯一的一人离开,然后三人自杀。
现在,约瑟夫斯不想被谋杀或自杀。他宁愿被罗马人俘虏,并面临一个问题。他必须弄清楚他应该围成一个圈坐(假设总共有n个人,而坐在位置1的那个人有第一个谋杀的机会),以便他是最后一个站立的人,而不是自杀。将投降给罗马人。
模式
如果对n的不同值进行计算,则会在此处找到一个模式。如果n为2的真次幂,则答案始终为1。每n大于2的次幂,则答案增加2。
n soldiers | 2a+ l | Survivor W(n) = 2l + 1 |
---|---|---|
1 | 1 + 0 | 2 * 0 + 1 = 1 |
2 | 2 + 0 | 2 * 0 + 1 = 1 |
3 | 2 + 1 | 2 * 1 + 1 = 3 |
4 | 4 + 0 | 2 * 0 + 1 = 1 |
5 | 4 + 1 | 2 * 1 + 1 = 3 |
6 | 4 + 2 | 2 * 2 + 1 = 5 |
7 | 4 + 3 | 2 * 3 + 1 = 7 |
8 | 8 + 0 | 2 * 0 + 1 = 1 |
9 | 8 + 1 | 2 * 1 + 1 = 3 |
10 | 8 + 2 | 2 * 2 + 1 = 5 |
11 | 8 + 3 | 2 * 3 + 1 = 7 |
12 | 8 + 4 | 2 * 4 + 1 = 9 |
现在,对于每个n,可以通过从数字中减去2的最大可能幂来找出约瑟夫斯的正确位置,我们得到了答案(假设n的值不是2的纯幂,否则答案为1)
N = 2 a +某物
其中,a =可能的最大功率
绝招
每当有人谈论2的幂时,想到的第一个单词是“二进制”。解决这个问题的方法是,用二进制比用十进制更容易,更短。这有一个窍门。由于我们需要扣除二进制的最大可能幂,因此该数字是最高有效位。在最初的约瑟夫斯问题中,还有另外40名士兵以及约瑟夫斯,使n = 41 。二进制数中的41是101001。如果将MSB(即最左边的1)移到最右边,则会得到010011,即19(十进制),这就是答案。在所有情况下都是如此。使用位操作可以轻松完成此操作。
C++
// C++ program for josephus problem
#include
using namespace std;
// function to find the position of the Most
// Significant Bit
int msbPos(int n)
{
int pos = 0;
while (n != 0) {
pos++;
// keeps shifting bits to the right
// until we are left with 0
n = n >> 1;
}
return pos;
}
// function to return at which place Josephus
// should sit to avoid being killed
int josephify(int n)
{
/* Getting the position of the Most Significant
Bit(MSB). The leftmost '1'. If the number is
'41' then its binary is '101001'.
So msbPos(41) = 6 */
int position = msbPos(n);
/* 'j' stores the number with which to XOR the
number 'n'. Since we need '100000'
We will do 1<<6-1 to get '100000' */
int j = 1 << (position - 1);
/* Toggling the Most Significant Bit. Changing
the leftmost '1' to '0'.
101001 ^ 100000 = 001001 (9) */
n = n ^ j;
/* Left-shifting once to add an extra '0' to
the right end of the binary number
001001 = 010010 (18) */
n = n << 1;
/* Toggling the '0' at the end to '1' which
is essentially the same as putting the
MSB at the rightmost place. 010010 | 1
= 010011 (19) */
n = n | 1;
return n;
}
// hard coded driver main function to run the program
int main()
{
int n = 41;
cout <
C
// C program for josephus problem
#include
// function to find the position of the Most
// Significant Bit
int msbPos(int n)
{
int pos = 0;
while (n != 0) {
pos++;
// keeps shifting bits to the right
// until we are left with 0
n = n >> 1;
}
return pos;
}
// function to return at which place Josephus
// should sit to avoid being killed
int josephify(int n)
{
/* Getting the position of the Most Significant
Bit(MSB). The leftmost '1'. If the number is
'41' then its binary is '101001'.
So msbPos(41) = 6 */
int position = msbPos(n);
/* 'j' stores the number with which to XOR the
number 'n'. Since we need '100000'
We will do 1<<6-1 to get '100000' */
int j = 1 << (position - 1);
/* Toggling the Most Significant Bit. Changing
the leftmost '1' to '0'.
101001 ^ 100000 = 001001 (9) */
n = n ^ j;
/* Left-shifting once to add an extra '0' to
the right end of the binary number
001001 = 010010 (18) */
n = n << 1;
/* Toggling the '0' at the end to '1' which
is essentially the same as putting the
MSB at the rightmost place. 010010 | 1
= 010011 (19) */
n = n | 1;
return n;
}
// hard coded driver main function to run the program
int main()
{
int n = 41;
printf("%d\n", josephify(n));
return 0;
}
Java
// Java program for josephus problem
public class GFG
{
// method to find the position of the Most
// Significant Bit
static int msbPos(int n)
{
int pos = 0;
while (n != 0) {
pos++;
// keeps shifting bits to the right
// until we are left with 0
n = n >> 1;
}
return pos;
}
// method to return at which place Josephus
// should sit to avoid being killed
static int josephify(int n)
{
/* Getting the position of the Most Significant
Bit(MSB). The leftmost '1'. If the number is
'41' then its binary is '101001'.
So msbPos(41) = 6 */
int position = msbPos(n);
/* 'j' stores the number with which to XOR the
number 'n'. Since we need '100000'
We will do 1<<6-1 to get '100000' */
int j = 1 << (position - 1);
/* Toggling the Most Significant Bit. Changing
the leftmost '1' to '0'.
101001 ^ 100000 = 001001 (9) */
n = n ^ j;
/* Left-shifting once to add an extra '0' to
the right end of the binary number
001001 = 010010 (18) */
n = n << 1;
/* Toggling the '0' at the end to '1' which
is essentially the same as putting the
MSB at the rightmost place. 010010 | 1
= 010011 (19) */
n = n | 1;
return n;
}
// Driver Method
public static void main(String[] args)
{
int n = 41;
System.out.println(josephify(n));
}
}
Python3
# Python3 program for josephus problem
# Function to find the position
# of the Most Significant Bit
def msbPos(n):
pos = 0
while n != 0:
pos += 1
n = n >> 1
return pos
# Function to return at which
# place Josephus should sit to
# avoid being killed
def josephify(n):
# Getting the position of the Most
# Significant Bit(MSB). The leftmost '1'.
# If the number is '41' then its binary
# is '101001'. So msbPos(41) = 6
position = msbPos(n)
# 'j' stores the number with which to XOR
# the number 'n'. Since we need '100000'
# We will do 1<<6-1 to get '100000'
j = 1 << (position - 1)
# Toggling the Most Significant Bit.
# Changing the leftmost '1' to '0'.
# 101001 ^ 100000 = 001001 (9)
n = n ^ j
# Left-shifting once to add an extra '0'
# to the right end of the binary number
# 001001 = 010010 (18)
n = n << 1
# Toggling the '0' at the end to '1'
# which is essentially the same as
# putting the MSB at the rightmost
# place. 010010 | 1 = 010011 (19)
n = n | 1
return n
# Driver Code
n = 41
print (josephify(n))
# This code is contributed by Shreyanshi Arun.
C#
// C# program for Josephus Problem
using System;
public class GFG
{
// Method to find the position
// of the Most Significant Bit
static int msbPos(int n)
{
int pos = 0;
while (n != 0) {
pos++;
// keeps shifting bits to the right
// until we are left with 0
n = n >> 1;
}
return pos;
}
// method to return at which place Josephus
// should sit to avoid being killed
static int josephify(int n)
{
// Getting the position of the Most Significant
// Bit(MSB). The leftmost '1'. If the number is
// '41' then its binary is '101001'.
// So msbPos(41) = 6
int position = msbPos(n);
// 'j' stores the number with which to XOR
// the number 'n'. Since we need '100000'
// We will do 1<<6-1 to get '100000'
int j = 1 << (position - 1);
// Toggling the Most Significant Bit.
// Changing the leftmost '1' to '0'.
// 101001 ^ 100000 = 001001 (9)
n = n ^ j;
// Left-shifting once to add an extra '0'
// to the right end of the binary number
// 001001 = 010010 (18)
n = n << 1;
// Toggling the '0' at the end to '1' which
// is essentially the same as putting the
// MSB at the rightmost place. 010010 | 1
// = 010011 (19)
n = n | 1;
return n;
}
// Driver code
public static void Main()
{
int n = 41;
Console.WriteLine(josephify(n));
}
}
// This code is contributed by vt_m .
PHP
> 1;
}
return $pos;
}
// function to return at which place Josephus
// should sit to avoid being killed
function josephify($n)
{
/* Getting the position of the Most
Significant Bit(MSB). The leftmost '1'.
If the number is '41' then its binary
is '101001'. So msbPos(41) = 6 */
$position = msbPos($n);
/* 'j' stores the number with which to
XOR the number 'n'. Since we need
'100000'. We will do 1<<6-1 to get '100000' */
$j = 1 << ($position - 1);
/* Toggling the Most Significant Bit.
Changing the leftmost '1' to '0'.
101001 ^ 100000 = 001001 (9) */
$n = $n ^ $j;
/* Left-shifting once to add an extra '0'
to the right end of the binary number
001001 = 010010 (18) */
$n = $n << 1;
/* Toggling the '0' at the end to '1' which
is essentially the same as putting the
MSB at the rightmost place. 010010 | 1
= 010011 (19) */
$n = $n | 1;
return $n;
}
// Driver Code
$n = 41;
print(josephify($n));
// This code is contributed by mits
?>
输出:
19
参考:
- 亲爱的
- 维基百科
以前有关同一主题的文章:
- 约瑟夫斯问题|集合1(AO(n)解)
- 约瑟夫斯问题|集合2(k = 2时的简单解决方案)