1 约瑟夫问题

目录

问题

思路

代码


问题

约瑟夫问题 (本题要求用循环链表实现)

约瑟夫问题是一个经典的问题。已知n个人(不妨分别以编号1,2,3,…,n 代表 )围坐在一张圆桌周围,从编号为 k 的人开始,从1开始顺时针报数1, 2, 3, ...,顺时针数到m 的那个人,出列并输出。然后从出列的下一个人开始,从1开始继续顺时针报数,数到m的那个人,出列并输出,…依此重复下去,直到圆桌周围的人全部出列。

输入:n, k, m

输出:按照出列的顺序依次输出出列人的编号,编号中间相隔一个空格,每10个编号为一行。

非法情况

a)

输入::nkm任一个小于1
输出:n,m,k must bigger than 0.

b)

输入:k>n

输出:k should not bigger than n.

合法情况

输入:9,3,2

输出:4 6 8 1 3 7 2 9 5

思路

建立一个循环链表, 将最后一个节点的 next 连接到 head->next 上, 形成一个循环

删掉被叫到的人的节点, 直到只剩下一个人。

代码里名字起的有些随意呜呜, 最好还是规范一点。

代码

#include <cstdio>  
#include <iostream>   
#include <cstdlib>  
using namespace std;  
typedef struct Xhlb//循环链表   
{  
    int shu;  
    struct  Xhlb *xia;  
}xhlb;  
xhlb *tou;  

xhlb *chuangjian(int n)//创建链表函数 
{  
    tou = new xhlb;  
    xhlb *pre = tou;  
    for(int j = 0; j < n; j++)  
    {  
        xhlb *pp = new xhlb;  
        pp->shu = j+1;  
        pp->xia = NULL;  
        pre->xia = pp;  
        pre = pp;       
    }  
    pre->xia = tou->xia;//将首尾相连 
    return tou;  
}  
  
int main()  
{  
    int n, m, k; int i, j, flag = 0, ge = 0;   
    scanf("%d,%d,%d",&n,&k,&m);  
    if(n<1 || k<1 || m<1)//非法   
    {  
        printf("n,m,k must bigger than 0.\n");  
        return 0;  
    }  
    if(k > n)  
    {  
        printf("k should not bigger than n.\n");  
        return 0;  
    }  
      
    if(n==1)   //特殊情况,但乐学似乎没有这个例子
    {  
        printf("1\n");  
        return 0;  
    }  
    if(m==1)   //特殊情况,但乐学似乎没有这个例子 
    {  
        for(i = 0; i < n; i++)  
        {  
            printf("%d",k);  
            ge++;k++;  
            if(k>n) k=1;  
            if(ge==10)  
            {  
                printf("\n");ge=0;  
            }  
            else   
            {  
                printf(" ");  
            }  
        }printf("\n");  
        return 0;  
    }  
      
    ge = 0;  
    xhlb *biao = chuangjian(n);//创建链表   
    for(j = 0; j < k; j++)  
    {  
        biao = biao->xia;  
    }  
    for(i = 0;  ; i++)  
    {  
        flag++;  
        if(flag+1 == m)   
        {  
            printf("%d",biao->xia->shu);  
            ge++;  
            if(ge == 10)  
            {  
                printf("\n");ge=0;  
            }  
            else   
            {  
                printf(" ");  
            }  
            xhlb *tem = biao->xia;  
            biao->xia = biao->xia->xia;  
            delete tem; //删除被叫到的节点 
			flag = 0; //重置 
			biao = biao->xia;  
            if(biao->shu == biao->xia->shu) break; //是否仅剩一个人 
        }  
        else biao = biao->xia;  
    }  
    printf("%d\n",biao->xia->shu);  
    free(biao);  
    free(tou);  
    return 0;  
}  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值