千家信息网

如何编写约瑟夫环问题

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"如何编写约瑟夫环问题",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何编写约瑟夫环问题"吧!约瑟夫环问题的原来描述为,设有编号为1
千家信息网最后更新 2026年11月03日如何编写约瑟夫环问题

这篇文章主要讲解了"如何编写约瑟夫环问题",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何编写约瑟夫环问题"吧!

约瑟夫环问题的原来描述为,设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。 稍微简化一下。

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

思路:容易想到的就是用环链表来做,构建一个环链表,每个结点的编号为0, 1, ...... n-1。每次从当前位置向前移动m-1步,然后删除这个结点。最后剩下的结点就是胜利者。给出两种方法实现,一种是自定义链表操作,另一种用是STL库的单链表。不难发现,用STL库可以提高编写速度。

struct ListNode{    int num;        //编号    ListNode *next; //下一个    ListNode(int n = 0, ListNode *p = NULL)     { num = n; next = p;}}; //自定义链表实现int JosephusProblem_Solution1(int n, int m){    if(n < 1 || m < 1)        return -1;     ListNode *pHead = new ListNode(); //头结点    ListNode *pCurrentNode = pHead;   //当前结点    ListNode *pLastNode = NULL;       //前一个结点    unsigned i;     //构造环链表    for(i = 1; i < n; i++)    {        pCurrentNode->next = new ListNode(i);        pCurrentNode = pCurrentNode->next;    }    pCurrentNode->next = pHead;     //循环遍历    pLastNode = pCurrentNode;    pCurrentNode = pHead;     while(pCurrentNode->next != pCurrentNode)    {        //前进m - 1步        for(i = 0; i < m-1; i++)        {            pLastNode = pCurrentNode;            pCurrentNode = pCurrentNode->next;        }        //删除报到m - 1的数        pLastNode->next = pCurrentNode->next;        delete pCurrentNode;        pCurrentNode = pLastNode->next;    }    //释放空间    int result = pCurrentNode->num;    delete pCurrentNode;     return result;}//使用标准库int JosephusProblem_Solution2(int n, int m){    if(n < 1 || m < 1)        return -1;     list listInt;    unsigned i;    //初始化链表    for(i = 0; i < n; i++)        listInt.push_back(i);     list::iterator iterCurrent = listInt.begin();    while(listInt.size() > 1)    {        //前进m - 1步        for(i = 0; i < m-1; i++)        {            if(++iterCurrent == listInt.end())                iterCurrent = listInt.begin();        }        //临时保存删除的结点        list::iterator iterDel = iterCurrent;        if(++iterCurrent == listInt.end())            iterCurrent = listInt.begin();        //删除结点        listInt.erase(iterDel);    }     return *iterCurrent;}

上述方法的效率很低,其时间复杂度为O(mn)。当n和m很大时,很难在短时间内得出结果。不过好处就是可以给出n个人出圈的次序。只要在删除前保存一下即可。

下面利用数学推导,如果能得出一个通式,就可以利用递归、循环等手段解决。下面给出推导的过程:

(1)第一个被删除的数为 (m - 1) % n。

(2)假设第二轮的开始数字为k,那么这n - 1个数构成的约瑟夫环为k, k + 1, k + 2, k +3, .....,k - 3, k - 2。做一个简单的映射。

k -----> 0
k+1 ------> 1
k+2 ------> 2
...
...
k-2 ------> n-2

这是一个n -1个人的问题,如果能从n - 1个人问题的解推出 n 个人问题的解,从而得到一个递推公式,那么问题就解决了。假如我们已经知道了n -1个人时,最后胜利者的编号为x,利用映射关系逆推,就可以得出n个人时,胜利者的编号为 (x + k) % n。其中k等于m % n。代入(x + k) % n <=> (x + (m % n))%n <=> (x%n + (m%n)%n)%n <=> (x%n+m%n)%n <=> (x+m)%n

(3)第二个被删除的数为(m - 1) % (n - 1)。

(4)假设第三轮的开始数字为o,那么这n - 2个数构成的约瑟夫环为o, o + 1, o + 2,......o - 3, o - 2.。继续做映射。

o -----> 0
o+1 ------> 1
o+2 ------> 2
...
...

o-2 ------> n-3

这是一个n - 2个人的问题。假设最后的胜利者为y,那么n -1个人时,胜利者为 (y + o) % (n -1 ),其中o等于m % (n -1 )。代入可得 (y+m) % (n-1)
要得到n - 1个人问题的解,只需得到n - 2个人问题的解,倒推下去。只有一个人时,胜利者就是编号0。下面给出递推式:

f [1] = 0;
f [ i ] = ( f [i -1] + m) % i; (i>1)

有了递推公式,实现就非常简单了,给出循环的两种实现方式。再次表明用标准库的便捷性。

int JosephusProblem_Solution3(int n, int m){    if(n < 1 || m < 1)        return -1;     int *f = new int[n+1];    f[0] = f[1] = 0;        //f[0]其实用不到的     for(unsigned i = 2; i <= n; i++)        f[i] = (f[i-1] + m) % i; //按递推公式进行计算     int result = f[n];    delete []f;     return result;}int JosephusProblem_Solution4(int n, int m){    if(n < 1 || m < 1)        return -1;     vector f(n+1,0);    for(unsigned i = 2; i <= n; i++)        f[i] = (f[i-1] + m) % i;     return f[n];}

感谢各位的阅读,以上就是"如何编写约瑟夫环问题"的内容了,经过本文的学习后,相信大家对如何编写约瑟夫环问题这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

个人 问题 结点 约瑟 约瑟夫 胜利者 胜利 就是 报到 公式 环链 学习 循环 个数 内容 思路 数字 方法 时间 标准 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技 广州万易互联网科技有限公司 互联网科技有限公司图片 互联网络科技有限公司 奇酷互联网科技 互联网与新科技 小马过河互联网科技 无线互联网科技 亿账通互联网科技 上海卓越科技 互联网 荆州市昕露互联网络科技有限公司 江阴互联网智能科技产品进口 互联网5g黑科技有哪些 中国互联网有什么科技 下一代互联网重大应用科技园 全球科技与互联网公司市值变化 版纳互联网科技选哪家 银川新华互联网科技学校是国营吗 好易买互联网科技 互联网科技自媒体灵感 科技赋能下的互联网金融 互联网科技有限公司经营范围 互联网科技公司怎么样 华服互联网科技官网 彤创互联网科技有限公司 互联网科技公司有风险吗 乌苏新华互联网科技做什么的 恒生互联网科技业指数调整周期 普陀区互联网教育科技管理办法 北京瑞云互联网科技有限公司
0