约瑟夫问题 三种实现方法

约瑟夫问题的描述:有N个人坐成一圈,编号为1之N,从编号为1的人开始传递热马铃薯,M次传递之后,持有马铃薯的人退出游戏,然后从退出人的下一个继续游戏,传递M次之后,持有人退出继续游戏。最终留下来的人获胜。


用list实现

list<int> JosephusProblem_solution1(int m,int n){
    list<int> jose;//用于编号1至N
    list<int> res;//用于记录退出编号的次序;
    int mp;
    for(int i=1;i<=n;i++){
        jose.push_back(i);//编号
    }

    list<int>::iterator litr=jose.begin();
    //这里必须明白list.begin()和list.end()
    //为什么litr只自加m-1次?
    //为什么jose.end()时litr=jose.end(),而不用litr++?
   for(int i=0;i<n;i++){
        for(int j=0;j<m-1;j++){
            if(++litr==jose.end()){
                litr=jose.begin();
            }
        }
        list<int>::iterator del = litr;
        res.push_back(*litr);
        //避免删除最后一个元素时,找不到下一个起始点
        if(++litr==jose.end()){
            litr=jose.begin();
        }
        jose.erase(del);
    }
    return res;
}

单向循环链表实现

int JosephusProblem_solution3(int m,int n){
    if(n<1||m<1){
        return -1;
    }
    struct listNode{
        int num;
        struct listNode *next;
        listNode(int n=0,listNode *p = NULL){
            num=n;next = p;
        }
    };
    listNode *head = new listNode(1);
    listNode *CurrentNode = head;
    listNode *tail = NULL;
    for(int i=2;i<=n;i++){
        CurrentNode->next=new listNode(i);
        CurrentNode = CurrentNode->next;
    }
    CurrentNode->next = head;
    tail=CurrentNode;
    free(CurrentNode);
    //cout<<"--------------"<<endl;
    //这里自己画图就可以理解
    //head为tail的前一个节点,且同步移动
    //移动M次后tail->next = head->next,即删除了第M个元素,
    //再将head作为tail前一个元素即可
    while(tail!=head){
        for(int i=0;i<m-1;i++){
            tail=head;
            head=head->next;
        }
        tail->next = head->next;
        free(head);
        head=tail->next;
    }
    //cout<<tail->num<<endl;
    return tail->num;
}

数学方法实现

int JosephusProblem_solution2(int m,int n){
    if(m<1||n<1){
        return -1;
    }
    int *res = new int[n+1];
    res[1] = 0;
    for(int i=2;i<=n;i++){
        res[i] = (res[i-1]+m)%i;
    }
    int result = res[n];
    delete []res;
    return result+1;
}

有不严谨的地方,见谅!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值