问题描述
是否可以在 O(n)的约瑟夫斯问题中打印出移除顺序?
示例
人数为n = 7
,跳过人数为k = 3
。淘汰的顺序为:
3,6,2,7,5,1,4
我已经尝试过该算法,但仅适用于n <= 10^4
,我需要一种算法,该算法可以在 1秒以内
n <= 10^8
解决方法
有一种使用有序集的方法
(https://www.geeksforgeeks.org/ordered-set-gnu-c-pbds/):
- 初始化一个有序集合 V,并将[1,N]范围内的元素插入到V中。
- 初始化一个变量,比如 pos 为 0,以存储被移除元素的索引。
- 迭代直到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))
为了更好地理解,我建议您观看此视频: