Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 大k上的Josephus序列_C++_Algorithm_Linked List_Computer Science_Josephus - Fatal编程技术网

C++ 大k上的Josephus序列

C++ 大k上的Josephus序列,c++,algorithm,linked-list,computer-science,josephus,C++,Algorithm,Linked List,Computer Science,Josephus,在约瑟夫斯问题中,我们有n个人,从1到n。每一回合你跳过k个人,杀死下一个人。通常你会打印我对受害者序列感兴趣的最后一个幸存者。我试图通过基于在线建议的循环链接列表来实现这一点。当输入像n=123456这样大时,我的算法仍然不够快;k=100000000。我的时间目标不到一秒。我认为时间复杂度是O(nk),因为所有的链表操作都是O(1),对于每个人,我必须打印它们的值,并且可能移动k步。我是否应该找到一些不同的策略?我是否缺少一些明显的优化技术 #include <vector> u

在约瑟夫斯问题中,我们有n个人,从1到n。每一回合你跳过k个人,杀死下一个人。通常你会打印我对受害者序列感兴趣的最后一个幸存者。我试图通过基于在线建议的循环链接列表来实现这一点。当输入像n=123456这样大时,我的算法仍然不够快;k=100000000。我的时间目标不到一秒。我认为时间复杂度是O(nk),因为所有的链表操作都是O(1),对于每个人,我必须打印它们的值,并且可能移动k步。我是否应该找到一些不同的策略?我是否缺少一些明显的优化技术

#include <vector>
using namespace std;
 
struct Node {
    int value;
    struct Node* next;
};
 
Node* insertToEmpty(struct Node* last, int x) {
    Node* temp = (struct Node*)malloc(sizeof(struct Node));
    temp->value = x;
    last = temp;
    last->next = last;
    return last;
}
 
Node* insert(struct Node* last, int x) {
    if (last == NULL) {
        return insertToEmpty(last, x);
    }
    Node* temp = (struct Node*)malloc(sizeof(struct Node));
    temp->value = x;
    temp->next = last->next;
    last->next = temp;
    last = temp;
    return last;
}
 
Node* delete2(struct Node* prev, struct Node* current) {
    prev->next = current->next;
    return current->next;
}
 
int main() {
    int n;
    int k;
    cin >> n;
    cin >> k;
    if (n == 1) {
        cout << 1;
    }
    else {
        struct Node* curr;
        struct Node* prev;
        struct Node* last = NULL;
        for (int i = 1; i <= n; i++) {
            last = insert(last, i);
        }
        curr = last->next;
        prev = curr;
        for (int i = 1; i <= k%n; i++) {
            prev = curr;
            curr = curr->next;
        }
        do {
            cout << curr->value << " ";
            curr = delete2(prev, curr);
            n--;
            for (int j = 0; j < k%n; j++) {
                prev = curr;
                curr = curr->next;
            }
        } while (n > 1);
        cout << curr->value << endl;
 
    }
 
}
#包括
使用名称空间std;
结构节点{
int值;
结构节点*下一步;
};
节点*insertToEmpty(结构节点*last,int x){
Node*temp=(struct Node*)malloc(sizeof(struct Node));
温度->值=x;
最后=温度;
last->next=last;
最后返回;
}
节点*插入(结构节点*最后一个,int x){
if(last==NULL){
返回insertToEmpty(最后一个,x);
}
Node*temp=(struct Node*)malloc(sizeof(struct Node));
温度->值=x;
临时->下一步=上一步->下一步;
最后->下一步=温度;
最后=温度;
最后返回;
}
节点*delete2(结构节点*prev,结构节点*current){
上一个->下一个=当前->下一个;
返回当前->下一步;
}
int main(){
int n;
int k;
cin>>n;
cin>>k;
如果(n==1){
cout(1);

cout value使用简单链表是正确的
O(nk)
,如果要加快速度,必须使用更好的数据结构。我建议您使用a的变体来解决此问题

跳过列表是一种二维结构。所有值都位于底部。向上的每一级仅包含部分值。它跳过其他值。如果要移动固定数量的步数,则可以向前和向上移动,跳过元素,直到可以向前和向下移动到正确的位置。所有操作都是对数的。在y中我们的例子将使算法
O(n(log(n)+log(k))

使用此结构,节点的外观如下所示:

struct Node {
    int value;
    int count;
    struct Node* parent;
    struct Node* next;
    struct Node* first_child;
};
当您构建它时,您的底层将如下所示:

1 <-> 2 <-> 3 <-> ... <-> n
1 <-> 3 <-> 5 <-> ... <-> (n-1 or n as appropriate)
1 <-> 5 <-> 9 <-> 13 <-> ... <-> (something from n-3 to n)
第一个\u子项
指向下面层中的相同值时,您的
父项
指向上一层,并且
计数
为2

您的第三层看起来像:

1 <-> 2 <-> 3 <-> ... <-> n
1 <-> 3 <-> 5 <-> ... <-> (n-1 or n as appropriate)
1 <-> 5 <-> 9 <-> 13 <-> ... <-> (something from n-3 to n)
此操作需要
O(log(n))
时间,因为这是有多少个级别

接下来,我们需要一个小的辅助函数来查找块中的最后一个节点。这意味着我们要向下向右移动,直到到达该节点

Node* last_in_block (Node* node) {
    if (node->next == null) {
        /* Slide down the end. */
        while (node->first_child != null) {
            node = node->first_child;
        }
    }
    else {
        while (node->first_child != null) {
            Node* child = node->first_child;
            while (child->next->parent == node) {
                child = child->next;
            }
            node = child;
        }
    }
    return node;
}
现在我们向前走几步怎么样?这有点棘手

首先让我们同意,在一个特定的地点意味着“我刚刚访问过这里,正在继续”。因此,我们可以递归地将
move
定义为“寻找要跳过的节点,然后从块中减去其计数”。但也有一些边缘情况。同样,未经测试的代码,但下面应该给出我的意思的一般概念

Node* move (Node* node, int steps) {
    if (node->next == null) {
        /* We are at the end, go to the top */
        while (node->parent != null) {
            node = node->parent;
        }

        /* Go around the loop as many times as needed. */
        steps = steps % node->count;

        /* Travel down to the right level to continue our journey */
        while (steps < node->count) {
            node = node->first_child;
        }

        /* And step over this node */
        steps -= node->count;
    }

    if (steps <= 0) {
        /* EXIT HERE IF JOURNEY IS ENDED */
        return last_in_block(node);
    }

    /* Right now the following are true.

       1. We are not at the end.
       2. We are also not at the top level (because the node there is at the end).
       3. node->next is also not at the top level (because it is at our level).
       4. 0 < steps, so traveling down we will eventually find a doable step.
    */

    if (steps <= node->next->count) {
        /* travel forward, then down to the right level. */
        node = node->next;
        while (steps < node->count) {
            node = node->first_child;
        }
    }
    else if (node->parent != node->next->parent && node->next->parent->count < steps) {
        /* travel forward and then up */
        node = node->next;
        while (node->parent != null && node->parent->count < steps) {
            node = node->parent;
        }
    }
    else {
        /* just travel forward */
        node = node->next;
    }
    /* And now we step over the block represented by this node. */
    steps -= node->count;
    return move(node, steps);
}
节点*移动(节点*节点,整数步){
如果(节点->下一步==null){
/*我们已经到了终点,爬到顶端*/
while(节点->父节点!=null){
节点=节点->父节点;
}
/*根据需要多次循环*/
步骤=步骤%node->count;
/*下到正确的高度继续我们的旅程*/
同时(步骤<节点->计数){
节点=节点->第一个子节点;
}
/*然后跨过这个节点*/
步骤-=节点->计数;
}
if(steps next)也不在顶级(因为它在我们的级别)。
4.0<步数,所以向下走,我们最终会找到一个可行的步骤。
*/
如果(步骤下一步->计数){
/*向前行驶,然后下降到正确的高度*/
节点=节点->下一步;
同时(步骤<节点->计数){
节点=节点->第一个子节点;
}
}
否则如果(节点->父节点!=节点->下一步->父节点和节点->下一步->父节点->计数<步骤){
/*向前走,然后向上走*/
节点=节点->下一步;
而(节点->父节点!=null&&node->父节点->计数父节点;
}
}
否则{
/*向前走*/
节点=节点->下一步;
}
/*现在我们跨过这个节点表示的块*/
步骤-=节点->计数;
返回移动(节点、步骤);
}

现在,使用此数据结构,您可以了解如何向前移动、移除您所站的位置、再次向前移动等等。

我们可以使用。
O(n log n)
k
中获得独立性

示例输入、输出:

stdin:   10 5
stdout:  4 9 5 1 8 7 0 3 6 
C++改编自Kimiyuki Onaka的代码:

#包括
#包括
#包括
#包括
使用名称空间std;
模板
结构图{
类型定义T值_类型;
typedef双键_类型;
v型值;
k型键;
共享的ptr l,r;
大小;
treap(v型值)
:v(v)
,k(生成())
,l()
,r()
,m_尺寸(1){
}
静态共享\u ptr更新(共享\u ptr const&t){
if(t){
t->m_尺寸=1+尺寸(t->l)+尺寸(t->r);
}
返回t;
}
静态密钥类型生成(){
静态随机激励装置;
静态默认_随机_引擎(设备());
静态均匀实分布区;
返回距离(发动机);
}
静态大小(共享大小){
返回t?t->m_大小:0;
}
静态共享\u ptr合并(共享\u ptr常量&a,共享\u ptr常量&b){//
如果(不是a)返回b;
如果(不是b)返回a;
如果(a->k>b->k){
a->r=合并(a->r,b);
返回更新(a);
}否则{
b->l=合并(a,b->l);
返回更新(b);
}
}