zoukankan      html  css  js  c++  java
  • Josephus(约瑟夫)问题分别用循环链表和数组实现

    
    
    #include<iostream>
    using namespace std;
    void Josephus(int n,int m,int k)
    {
        int *a=new int [10000],i;
        int count=0;//计算被退出的人数(n-1)
        int t=0;//1,2,3..m报数记数变量
        for(i=0;i<n;i++)
            a[i]=i+1;
        i=k-1;
        while(count<n-1)//只剩下一个时退出循环
        {
            if(a[i]!=0)
                t++;
            if(t==m)
            {
                t=0;//记数归0
                printf("%4d",a[i]);//依次输出删除的编号
                a[i]=0;//给删除的数组赋0
    
                count++;//退出人数加1    
            }
            i++;
            if(i==n)
                i=0;//报数到末尾后i恢复为0
        }
        for(i=0;i<n;i++)
            if(a[i]!=0)
            {
                printf("\n最后剩余的结点是:%4d\n",a[i]);
                return;
            }
    }
    int main()
    {
        int n,m,k;
        cout<<"请输入结点的个数:"<<endl;
        scanf("%d",&n);
        cout<<"请输入报道报数周期是:"<<endl;
        scanf("%d",&m);
        cout<<"请输入从第几个数开始报数:"<<endl;
        scanf("%d",&k);
        Josephus(n,m,k);
        return 0;
    }
    
    
    /*用数组实现约瑟夫问题比较上面的更复杂,自己想的,没参考书上的。*/
    #include<iostream>
    using namespace std;
    void Josephus(int n,int m,int k)
    {
        int *a=new int [10000],i;
        int count=0;//计算被退出的人数(n-1)
        int t=0;//1,2,3..m报数记数变量
        int l=1;//while退出循环条件
        for(i=0;i<n;i++)
            a[i]=i+1;
        while(l)
        {
            for(i=k-1;i<n;i++)
            {
                if(a[i]!=0)
                {
    
                    t++;
                    if(t==m)
                    {
                        t=0;//记数归0
                        printf("%4d",a[i]);//依次输出删除的编号
                        a[i]=0;//给删除的数组赋0
                        count++;//退出人数加1    
                    }
                }
                if(count==n-1)
                {
                    l=0;//循环终止
                    break;    
                }
            }
            k=1;//非第一次时将i变为从0开始
        }
        for(i=0;i<n;i++)
            if(a[i]!=0)
            {
                printf("\n最后剩余的结点是:%4d\n",a[i]);
                return;
            }
    }
    int main()
    {
        int n,m,k;
        cout<<"请输入结点的个数:"<<endl;
        scanf("%d",&n);
        cout<<"请输入报道报数周期是:"<<endl;
        scanf("%d",&m);
        cout<<"请输入从第几个数开始报数:"<<endl;
        scanf("%d",&k);
        Josephus(n,m,k);
        return 0;
    }
    /*用循环链表实现约瑟夫问题*/
    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    typedef struct LNode
    {
        int data;
        struct LNode *next;
    }LNode,*LinkList;
    void Josephus(int n,int m,int k)
    {
        LinkList p,r,list=NULL;
        int i;
        for(i=1;i<=n;i++)
        {
            p=(LinkList)malloc(sizeof(LNode));//申请一个新的链结点
            p->data=i;//存放第i个结点的编号
            if(list==NULL)
                list=p;
            else
                r->next=p;
            r=p;
        }
        p->next=list;//至此,建立一个循环链表
        p=list;
        for(i=1;i<k;i++)
        {
            r=p;
      /*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
            p=p->next;
        }//此时p指向第1个出发结点
        while(p->next!=p)
        {
            for(i=1;i<m;i++)
            {
                r=p;
                p=p->next;
            }//p指向第m个结点,r指向第m-1个结点
            r->next=p->next;//删除第m个结点
            printf("%4d",p->data);//依次输出删除结点的编号
            free(p);//释放被删除结点的空间
            p=r->next;//p指向新的出发结点
        }
        printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
    }
    int main()
    {
        int n,m,k;
        cout<<"请输入结点的个数:"<<endl;
        scanf("%d",&n);
        cout<<"请输入报道报数周期是:"<<endl;
        scanf("%d",&m);
        cout<<"请输入从第几个数开始报数:"<<endl;
        scanf("%d",&k);
        Josephus(n,m,k);
        return 0;
    }
    /*任务:
    一群小孩围成一圈,任意假定一个数m,从第一个小孩起,顺时针方向数,每数到第m个小孩时,该小孩便离开。小孩不断离开,圈子不断缩小。最后剩下的一个小孩便是胜者。求胜者的编号?
    要求
    以面向对象技术进行程序设计
    建立环状链表类
    程序便于维护与扩张:如易于对小孩数量n和数数间隔m进行变化
    改变获胜者数量,使其可设为任意值
    可中途增加小孩人数
    */
    /*结构体实现*/
    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    typedef struct LNode
    {
        int data;
        struct LNode *next;
    }LNode,*LinkList;
    class Jos
    {
    private:
        int n,m,k,last;//结点个数,报数周期,报数起始数.
        int index;//标记剩余人数,标记插入时r第一个的指向.
        LinkList list,r;
    public:
        Jos(){list=NULL;r=NULL;}
        void set();
        void Josephus();
        void Insert();
        void is_add();
        void print_Josephus();
    }XPY;
    void Jos:: set()//插入函数
    {
        cout<<"请输入结点的个数:"<<endl;
        scanf("%d",&n);
        cout<<"请输入报道报数周期是:"<<endl;
        scanf("%d",&m);
        cout<<"请输入从第几个数开始报数:"<<endl;
        scanf("%d",&k);
        cout<<"请输入剩余个数:"<<endl;
        scanf("%d",&last);
    }
    void Jos:: Josephus()//建立一个循环链表
    {
        LinkList p;
        int i;
        index=n;//结点个数赋初值
        for(i=1;i<=n;i++)
        {
            p=(LinkList)malloc(sizeof(LNode));//申请一个新的链结点
            p->data=i;//存放第i个结点的编号
            if(list==NULL)
                list=p;
            else
                r->next=p;
            r=p;
        }
        p->next=list;//至此,建立一个循环链表
    }
    void Jos:: Insert()//循环链表的插入
    {
        LinkList p=(LinkList)malloc(sizeof(LNode));
        p->data=n+1;
        n++;//个数加1
        index++;//个数加1
        p->next=r->next;
        r->next=p;
        r=p;
    }
    void Jos:: is_add()//中途添加函数
    {
        printf("是否添加成员(Y/N)\n");
        char ch;
        cin>>ch;
        while(1)
        {    
            system("cls");
            ch=tolower(ch);//转换为全小写的
            if(ch=='y')
                Insert();
            else if(ch=='n')
                break;
            else
                printf("输入有误\n");
            system("cls");
            printf("是否继续添加成员(Y/N)\n");
            cin>>ch;
        }
    }
    void Jos:: print_Josephus()//循环的执行
    {
        LinkList p=list;
        for(int i=1;i<k;i++)
        {
            r=p;
            /*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
            p=p->next;
        }//此时p指向第1个出发结点
        while(index>last)
        {
            for(i=1;i<m;i++)
            {
                r=p;
                p=p->next;
                
            }//p指向第m个结点,r指向第m-1个结点
            r->next=p->next;//删除第m个结点
            printf("删除的结点号是:%d\n\n",p->data);//依次输出删除结点的编号
            free(p);//释放被删除结点的空间
            is_add();
            p=r->next;//p指向新的出发结点
            index--;//删除结点,个数减1
        }
        while(index--)//胜利者的输出
        {
            printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
            p=p->next;
        }
    }
    int main()
    {
        XPY.set();
        XPY.Josephus();
        XPY.print_Josephus();
        return 0;
    }
    /*数组实现*/
    #include<iostream>
    using namespace std;
    class Jos
    {
    private:
        int *a,length,data;
        int n,m,k,last;//结点个数,报数周期,报数起始数.
    public:
        Jos()
        {
            a = new int [1000000];
        }
        void set();
        void is_add();
        void print_Josephus();
    }XPY;
    void Jos:: set()//插入函数
    {
        cout<<"请输入结点的个数:"<<endl;
        scanf("%d",&n);
        cout<<"请输入报道报数周期是:"<<endl;
        scanf("%d",&m);
        cout<<"请输入从第几个数开始报数:"<<endl;
        scanf("%d",&k);
        cout<<"请输入剩余个数:"<<endl;
        scanf("%d",&last);
    }
    void Jos:: is_add()//中途添加函数
    {
        printf("是否添加成员(Y/N)\n");
        char ch;
        cin>>ch;
        while(1)
        {
            ch=tolower(ch);//转换为全小写的
            if(ch=='y')
                a[n++]=n+1;
            else if(ch=='n')
                break;
            else
                printf("输入有误\n");
            printf("是否继续添加成员(Y/N)\n");
            cin>>ch;
        }
    }
    void Jos::print_Josephus()
    {
        int i;
        int count=0;//计算被退出的人数(n-1)
        int t=0;//1,2,3..m报数记数变量
        for(i=0;i<n;i++)
            a[i]=i+1;
        i=k-1;
        while(count<n-last)//只剩下一个时退出循环
        {
            if(a[i]!=0)
                t++;
            if(t==m)
            {
                t=0;//记数归0
                printf("删除的结点为:%4d\n",a[i]);//依次输出删除的编号
                a[i]=0;//给删除的数组赋0
                count++;//退出人数加1    
                is_add();
            }
            i++;
        
            if(i==n)
                i=0;//报数到末尾后i恢复为0
        }
        for(i=0;i<n;i++)
            if(a[i]!=0)
                printf("\n最后剩余的结点是:%4d\n",a[i]);
    }
    int main()
    {
        XPY.set();
        XPY.print_Josephus();
        return 0;
    }
        
  • 相关阅读:
    Linux上将文件夹复制到指令目录
    将PC版网页转为手机端自适应网页
    WCF初探-18:WCF数据协定之KnownType
    WCF初探-17:WCF数据协定之等效性
    WCF初探-16:WCF数据协定之基础知识
    WCF初探-15:WCF操作协定
    2018数学二21题解法分析
    柯西不等式:简单常考形式
    等价、合同、相似、正交变换;二次型,正定,惯性指数
    高数狄利克雷收敛条件(傅里叶)
  • 原文地址:https://www.cnblogs.com/heqinghui/p/2711709.html
Copyright © 2011-2022 走看看