约瑟夫环

转载自:https://www.cnblogs.com/daimingming/p/3242406.html

问题描述:

已知n个人(以编号0,2,3...n-1分别表示)围坐在一起。从编号为0的人开始报数,数到k的那个人出列;他的下一个人又从1开始报数,数到k的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列,最后一个出列的人为胜利者。求胜利者编号.

历史背景:

Wikipedia: 这个问题是以弗拉维奥·约瑟夫斯命名的,它是1世纪的一名犹太历史学家。

他在自己的日记中写道,他和他的40个战友被罗马军队包围在洞中。

他们讨论是自杀还是被俘,最终决定自杀,并以抽签的方式决定谁杀掉谁。约瑟夫斯和另外一个人是最后两个留下的人。

约瑟夫斯说服了那个人,他们将向罗马军队投降,不再自杀。约瑟夫斯把他的存活归因于运气或天意,他不知道是哪一个.

 

问题分析:解决该问题有两种思路,第一种:通过建立循环链表来模拟这个过程

                  第二种:通过递归方式(数学归纳将问题转化为数学问题)

 

由于递归方式,代码更简洁,下面首先以递归方式来解决问题

 

——————递归实现:

 

例如 对 m= 10,k=3

   0  1  2  3  4  5  6  7  8  9  (*)

     0  1  3  4  5  6  7  8  9    (* 循环下去)

转化为:       3  4  5  6  7  8  9  0  1  (* 循环下去)

    

             0  1  2  3  4  5  6  7  8

            

            m=10,k=3 去掉一个元素之后,变成了一个m=9,k=3的约瑟夫环问题

           并且有如下关系 

           3 = (0+3)%10   4 = (1+3)%10   ... 0 = (3+7)%10

         即 3 = (0+k)% m    4 =  (1+k) % m       ... 0  = (3+k) % m

          

          m =10,k =3 设约瑟夫环最后一个出列的人为 Joseph(10,3),那么存在如下关系

          Joseph(10,3) = (Joseph(9,3)+k) %m;

          ...

          Joseph(n,k) = (Joseph(n-1,k)+k) % n (n>1);

        

C++实现如下: 

递归方法一:

int Joseph(int m,int k)
{
    if(m<=0||k<=0)
    {
        cout<<"error!"<<endl;
        return -1;
    }else
    {
        if(m==1)
        {
            return 0;
        }else
        {
            return ((Joseph(m-1,k)+k)%m);
        }
    }
}

 递归方法二:如果输出整个出队的顺序

int Joseph(int m,int k,int i)
{
    if(m<=0||k<=0||m<i)
    {
        cout<<"error"<<endl;
        return -1;

    }else
    {
        if(i==1)
        {
            return (m+k-1)%m;
        }else
        {
            return ((Joseph(m-1,k,i-1)+k)%m);
        }
    }
}

程序运行结果如下:

int main()
{   
    cout<<"递归方法一"<<endl;
    cout << Joseph(6,3) << endl;
    cout<<"递归方法二"<<endl;
    for(int i=1;i<=6;i++)
    {
        cout<<Joseph(6,3,i)<<endl;
    }
    getchar();
    return 0;
}

  结果:

 

 ——————循环链表实现:

 

建立节点数据结构:循环链表

struct Node
{
    int data;
    Node * next;
};

struct LinkedList
{
    Node *pHead;
    Node *pTail;
    int len;
};

建立循环链表

 

//建立个节点
Node * GetNode(int i)
{
    Node * p = (Node *)malloc(sizeof(Node));
    if(p!=NULL&&i>=0)
    {
        p->data = i;
        p->next = NULL;
        return p;

    }else
    {

        cout<<"error"<<endl;
        exit(-1);
        return NULL;
    }
}

//建立链表
LinkedList* CreateLinkedList(int i)
{
    Node* node = GetNode(0);
    LinkedList *head = (LinkedList*)malloc(sizeof(LinkedList));
    if(head == NULL)
    {
        cout<<"CreateLinkedList:memory error"<<endl;
        exit(-1);
        return NULL;
    }
    if(i<=0)
    {
        cout<<"CreateLinkedList: error"<<endl;
        exit(-1);
        return NULL;
    }

    head->pHead = node;
    head->pTail = node;
    head->len = 1;
    if(i==1)
    {
        node->next = node;
    }else
    {
        Node *p = head->pHead;
        for(int j=1;j<=i-1;j++)
        {
            Node* node = GetNode(j);
            node->data = j;
            p->next = node;
            p=p->next;
            head->len++;
        }
        head->pTail = p;
        p->next = head->pHead;
    }
    return head;

}

 

删除节点:

 

//删除节点
void RemoveNode(LinkedList*head,Node *deleNode)
{
    Node* p = head->pHead;
    cout<<deleNode->data<<endl;
    if(p!=NULL){
        if(head->len>1){
            do
            {
                if(p->data==deleNode->data)
                {
                    if(p==head->pHead)
                    {
                        head->pHead = p->next;
                    }
                    if(p==head->pTail)
                    {
                        head->pTail = p->next;
                    }
                    p->data = p->next->data;
                    p->next = p->next->next;
                    head->len--;
                    return;

                }else{
                    p=p->next;
                }
            }while(p!=head->pHead);
        }else
        {
            cout<<"error";
            exit(-1);
            return;
        }
    }else
    {
        return;
    }
}

 

约瑟夫模拟:

int Joseph(int m,int k)
{
    if(m<=0||k<=0)
    {
        cout<<"error:input"<<endl;
        return -1;
    }
    LinkedList* list = CreateLinkedList(m);
    //Print_List(list);
    Node * p = list->pHead;

    for(int i=1;i<=k;i++)
    {
        if(list->len ==1)
        {
            return p->data;
        }
        if(i==k)
        {
            RemoveNode(list,p);
            i = 1;
        }
        p=p->next;
    }
    return 0;

}

 

 

程序运行结果如下:

int _tmain(int argc, _TCHAR* argv[])
{
    
    
    cout<<"循环列表"<<endl;
    cout<<Joseph(6,3)<<endl;
    getchar();
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值