约瑟夫环的问题(菜鸟)

661 阅读3分钟

#先描述一下这题目的由来

  • 在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中
  • 39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式
  • 41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀
  • 然后再由下一个让重新报数,直到所有人都自杀身亡为止
  • 他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

#数组方法

#include<iostream>//数组解决约瑟夫环问题;  
using namespace std;  
int main(){  
    int n,m,a[100]={0},i=0,cnt,k=0;  
    cin>>n>>m;  
    while(cnt!=(n-1))  
    {  
        i++;  
        if(i>n) i=1;//将首尾连接起来  
        if(a[i]==0){  
            k++;//开始报数  
            if(k==m){  
                a[i]=1;//报到三时就让这个人消失  
                k=0;//重新开始下一次报数  
                cnt++;//消失人数加一  
            }  
        }  
    }  
    for(int j=1;j<n+1;j++)  
        if(a[j]==0)  
            cout<<j<<" ";//输出最后一存活的人编号  
    return 0;  
}

链表方法

代码

#include<iostream>  
using namespace std;  
//用链表实现约瑟夫环问题 (循环链表)   
  
typedef struct node  //typedef用来重命名struct node这种数据类型,将其命名为Node,注意Node与node不一样
{  
    int data;  
    struct node* next;  
}Node;  
  
void ysflb(int N,int M)  //总共有N个人,报到数字为M的人出局   
{  
    //初始化循环链表  
    Node *head = NULL,*p=NULL,*r=NULL;   //head为头指针,指向链表的第一个结点,一开始赋值为NULL,代表不指向任何结点   
    head = (Node*)malloc(sizeof(Node));  //让head指向一个实际的空间  
    if(NULL==head)  //内存空间可能会申请失败,大多数情况不会申请失败   
    {  
        cout<<"Failed!";  
        return;//如果失败,就中止  
    }   
    head->data=1;       //从1开始编号   
    head->next=NULL;    //一开始整个链表只有一个Node(结点),这个Node有两个域,分别是data和next  
    //data从1开始,next指向NULL,总共需要N个结点,现在创建了一个,还需要N-1个   
    p=head;             //head要保持不能改变,才能够找到链表的起始位置,一开始p也指向第一个结点  
    //p等一下会被使用,用它可以便于创建剩下的N-1个结点   
    for(int i=2;i<=N;i++)  
    {  
        r=(Node*)malloc(sizeof(Node))
        r->data=i;  
        r->next=NULL;  
        //插入结点   
        p->next=r;  
        p=r;  
          
    }  
    //创建循环链表  
    p->next=head;   //最后一个结点的next指向头结点  
    p=head;         //为后续方便,将p指向头结点  
    cout<<"淘汰的顺序:"<<endl;  
    //约瑟夫环的模拟  
    while(p->next->next!= p)  //如果p的next=p,说明目前只有一个元素   
    {  
        for(int i=1;i<M;i++)  //报到数字为M的时候出局   
        {  
            r=p;   //保留出局的前一个结点   
            p=p->next; //p指向的是要出局的这个结点,需要保留前一个结点  
        }  
        // 输出  
        cout<<p->data<<" ";  
        r->next=p->next
        p=p->next;  //更新p重新进行报数   
    }   
    cout<<endl<<"剩下来的人的编号:"<<endl;  
    cout<<r->data<<" "<<p->data; //r是倒数第二个,p是倒数第一个  
}  

int main()  
{  
    int a,b;  
    cin>>a>>b;  
    ysflb(a,b);  
    return 0;  
}

链表小知识

p->next=q;//p后面跟上q
p=q->next;//将q的下一个节点给p
p->next=q-next;//让p的节点指向q节点的下一个数据,即跳过q节点

怎么理解呢