约瑟夫斯问题 |第 3 组(使用 STL)
给定N个人站在一个圆圈里,一个整数K。如果最初从第一个位置开始,从当前位置顺时针方向第K个活着的人被杀死,然后当前位置移动到(K+1)的位置th 活着的人,并执行相同的步骤,直到只剩下一个人,任务是打印最后一个活着的人的位置。
例子:
Input: N = 5, K = 2
Output: 3
Explanation:
One way to perform the operations is:
- Step 1: Initially, the counting starts from position 1. Therefore, the Kth alive person at position 2 is killed, so the remaining alive persons are at positions {1, 3, 4, 5}.
- Step 2: Now, the counting starts from position 3. Therefore, the Kth alive person at position 4 is killed, so the remaining alive persons are at positions {1, 3, 5}.
- Step 3: Now, the counting starts from position 5. Therefore, the Kth alive person at position 1 is killed, so the remaining alive persons are at positions {3, 5}.
- Step 4: Now, the counting starts from position 3. Therefore, the Kth alive person at position 5 is killed, so the last alive person is at position 3.
Therefore, the last remaining person living is at position 3.
Input: N = 10, K = 4
Output: 5
本文的 Set 1 和 Set 2 讨论了解决此问题的不同方法。
方法 1(使用向量): 上给定的 问题被称为 约瑟夫斯的 问题。可以使用 STL 库中的递归和向量数据结构来解决该问题。请按照以下步骤解决问题:
- 初始化一个向量,比如arr[]来存储所有人的位置。
- 使用变量i在[1, N]范围内迭代,并在每次迭代中将i附加到向量arr[] 。
- 定义一个递归函数,比如RecursiveJosephus(vector
:: iterator it, vector 它指向当前活着的人,从那里计算K个元素。arr), - 如果 向量的大小, arr为1,然后返回arr[0] 中的值。
- 在[1, K-1]范围内迭代,然后在每次迭代中将其递增1 ,如果相等,则arr。 end()然后将arr.begin()分配给它。
- 现在如果它指向向量arr 的最后一个元素,则弹出向量的最后一个元素arr ,然后用第(K+1)个活着的人的位置更新它,即arr.begin() 。
- 否则,将其指向的人的位置抹去。删除后,现在指向第(K+1 )个人的位置。
- 最后,完成上述步骤后,调用函数RecursiveJosephus(arr.begin(), arr)并将其返回的值打印为最后一个活着的人的位置。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Recursive auxiliary function to find
// vthe position of thevlast alive person
int RecursiveJosephus(vector& arr, int K,
vector::iterator it)
{
// If size of arr is 1
if (arr.size() == 1) {
return arr[0];
}
// Iterate over the range [1, K-1]
for (int i = 1; i < K; i++) {
// Increment it by 1
it++;
// If it is equal to arr.end()
if (it == arr.end()) {
// Assign arr.begin() to it
it = arr.begin();
}
}
// If it is equal to prev(arr.end())
if (it == prev(arr.end())) {
// Assign arr.begin() to it
it = arr.begin();
// Remove the last element
arr.pop_back();
}
else {
// Erase the element at it
arr.erase(it);
}
// Return the last alive person
return RecursiveJosephus(arr, K, it);
}
// Function to find the position of the
// last alive person
int Josephus(int N, int K)
{
// Stores positions of every person
vector arr;
for (int i = 1; i <= N; i++)
arr.push_back(i);
// Function call to find the position
// of the last alive person
return RecursiveJosephus(arr, K, arr.begin());
}
// Driver Code
int main()
{
// Given Input
int N = 5;
int K = 2;
// Function Call
cout << Josephus(N, K);
}
C++
// C++ program for the above approach
#include
using namespace std;
// Recursive auxiliary function to find
// the position of the last alive person
int RecursiveJosephus(set& arr, int K,
set::iterator it)
{
// If size of arr is 1
if (arr.size() == 1) {
return *it;
}
// Iterate over the range [1, K-1]
for (int i = 1; i < K; i++) {
// Increment it by 1
it++;
// If it is equal to arr.end()
if (it == arr.end()) {
// Assign arr.begin() to it
it = arr.begin();
}
}
// If it is equal to prev(arr.end())
if (it == prev(arr.end())) {
// Assign arr.begin() to it
it = arr.begin();
// Remove the last element
arr.erase(prev(arr.end()));
}
else {
// Stores the value pointed
// by next iterator of it
int val = (*next(it));
// Erase the element at it
arr.erase(it);
// Update it
it = arr.find(val);
}
// Return the position of
// the last alive person
return RecursiveJosephus(arr, K, it);
}
// Function to find the position
// of the last alive person
int Josephus(int N, int K)
{
// Stores all the persons
set arr;
for (int i = 1; i <= N; i++)
arr.insert(i);
// Function call to find the position
// of the last alive person
return RecursiveJosephus(arr, K, arr.begin());
}
// Driver Code
int main()
{
// Given Input
int N = 5;
int K = 2;
// Function Call
cout << Josephus(N, K);
}
输出
3
时间复杂度: O(N 2 )
辅助空间: O(N)
方法 2(使用 SET):可以使用递归和 STL 库中的集合数据结构来解决问题。请按照以下步骤解决问题:
- 初始化一个集合,比如arr来存储所有人的位置。
- 使用变量i在[1, N]范围内迭代,并在每次迭代中将i插入集合arr中。
- 定义一个递归函数,比如RecursiveJosephus(set
::iterator it, set 它指向当前活着的人的位置,从那里计算K个元素。arr), - 如果 集合arr的大小为1,然后返回迭代器指向的值it。
- 在[1, K-1]范围内迭代,然后在每次迭代中将其递增1 ,如果它等于arr。 end(),然后分配arr.begin()给它。
- 现在,如果它指向集合的最后一个元素arr的位置,则删除集合的最后一个元素arr ,然后用 第(K+1) 个人的位置,即arr.begin()。
- 否则,将它的下一个迭代器的值存储在一个变量中,比如val然后擦除它指向的位置。
- 删除后失效。因此,现在在集合arr中找到val的值,然后将其分配给它。现在它指向第(K+1)个活人的位置。
- 最后,完成上述步骤后,调用函数RecursiveJosephus(arr.begin(), arr)并将其返回的值打印为最后一个活人的位置。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Recursive auxiliary function to find
// the position of the last alive person
int RecursiveJosephus(set& arr, int K,
set::iterator it)
{
// If size of arr is 1
if (arr.size() == 1) {
return *it;
}
// Iterate over the range [1, K-1]
for (int i = 1; i < K; i++) {
// Increment it by 1
it++;
// If it is equal to arr.end()
if (it == arr.end()) {
// Assign arr.begin() to it
it = arr.begin();
}
}
// If it is equal to prev(arr.end())
if (it == prev(arr.end())) {
// Assign arr.begin() to it
it = arr.begin();
// Remove the last element
arr.erase(prev(arr.end()));
}
else {
// Stores the value pointed
// by next iterator of it
int val = (*next(it));
// Erase the element at it
arr.erase(it);
// Update it
it = arr.find(val);
}
// Return the position of
// the last alive person
return RecursiveJosephus(arr, K, it);
}
// Function to find the position
// of the last alive person
int Josephus(int N, int K)
{
// Stores all the persons
set arr;
for (int i = 1; i <= N; i++)
arr.insert(i);
// Function call to find the position
// of the last alive person
return RecursiveJosephus(arr, K, arr.begin());
}
// Driver Code
int main()
{
// Given Input
int N = 5;
int K = 2;
// Function Call
cout << Josephus(N, K);
}
输出
3
时间复杂度: O(N*K+N*log(N))
辅助空间: O(N)