
算法科普:什么是约瑟夫环
3号被选出,离开圈子。 从4号开始重新计数,6号离开。 从7号开始重新计数,9号离开。 从10号开始重新计数,2号离开。 从4号开始重新计数,7号离开。 从8号开始重新计数,1号离开。 从4号开始重新计数,8号离开。 从10号开始重新计数,5号离开。 从10号开始重新计数,10号离开。最终剩下的胜利者是4号。
初始化数组flag,所有位置标记为1。 维护两个变量count和num,分别记录已出圈人数和当前报数器的值。 在每次循环中,遍历所有未离开的人,找到当前报数器所指的人。 如果找到第m个人的位置,将该位置标记为0,count加1。 当count等于n-1时,结束循环,剩下的位置即为胜利者。
发布日期:2021-05-19 23:03:46
浏览次数:31
分类:精选文章
本文共 3098 字,大约阅读时间需要 10 分钟。
约瑟夫环问题解析
问题描述
约瑟夫环(Josephus problem)是一个经典的数学问题。设想n个人围坐在圆桌旁,编号为1到n。从编号为k的位置开始报数,数到第m个人的时候,该人离开圈子。接下来的报数从下一个未离开的人继续,从1开始计数,依此类推,直到只剩下最后一个胜利者。
以10个人为例,k=3,m=3的情况下,游戏过程如下:
数组求解方法
解题思想
数组求解的核心思想是用一个一维数组来记录每个人的状态。初始时,所有人都处于圈内(标记为1)。当某人被选出时,标记为0,表示已出圈。同时,报数器清零,下一个未离开的人继续从1开始报数。
具体步骤:
代码实现
#include#define N 1000000int flag[N] = {0};int main() { int n, m; scanf("%d%d", &n, &m); int i = 0, count = 0, num = 0; for (i = 1; i <= n; i++) { flag[i] = 1; } while (count < n - 1) { for (i = 1; i <= n; i++) { if (flag[i]) { num++; if (num == m) { printf("%d\n", i); flag[i] = 0; count++; num = 0; if (count == n - 1) break; } } } } for (i = 1; i <= n; i++) { if (flag[i]) { printf("The last one is: %d\n", i); } } return 0;}
循环链表求解方法
解题思想
约瑟夫环问题也可以通过循环链表来模拟解决。每个节点表示一个人,next指针表示下一个在圈中的节点。当某人被选出时,删除该节点,调整next指针,形成新的环。
代码实现
#include#include typedef struct node { int number; struct node *next;} Node;Node* CreatNode(int x) { Node *p = (Node*)malloc(sizeof(Node)); p->number = x; p->next = NULL; return p;}Node* CreatJoseph(int n) { Node *head, *p, *q; for (p = q = 1; p <= n; p++) { p = CreatNode(p); if (p == 1) { head = p; } else { q->next = p; q = p; } } q->next = head; return head;}void RunJoseph(int n, int m) { Node *p, *q; p = CreatJoseph(n); while (p->next != p) { for (i = 1; i < m; i++) { p = p->next; } q = p->next; p->next = q->next; free(q); printf("%d--", q->number); } printf("\n最后剩下的数为:%d\n", p->number);}int main() { int n, m; scanf("%d%d", &n, &m); RunJoseph(n, m); return 0;}
递推公式求解方法
解题思想
约瑟夫环问题可以通过递推公式直接求解。已知f(n, m)表示n个人进行游戏中获胜者的编号,递推公式为:
f(n, m) = (f(n-1, m) + m) % n
其中,f(n-1, m)表示n-1个人时的胜利者编号。
递归代码实现
#includeint Joseph(int n, int m) { if (n <= 1 || m <= 1) return -1; if (n == 2) { if (m % 2 == 0) return 1; else return 2; } return (Joseph(n-1, m) + m - 1) % n + 1;}int main() { int n, m, x; scanf("%d%d", &n, &m); x = Joseph(n, m); printf("最后一个的编号是:%d\n", x); return 0;}
迭代代码实现
#includeint Joseph(int n, int m) { int i; int y = 1; if (m % 2 == 0) y = 1; else y = 2; for (i = 3; i <= n; i++) { x = (y - 1 + m) % i + 1; y = x; } return y;}int main() { int n, m, x; scanf("%d%d", &n, &m); x = Joseph(n, m); printf("最后一个人的编号是:%d\n", x); return 0;}
实际应用
约瑟夫环问题在实际生活中有广泛应用。例如,在团建活动中,可以将参赛人员按照约瑟夫环规则安排座位,确保心仪的对象和你坐在同一圈中,有机会共同进决赛圈。
发表评论
最新留言
很好
[***.229.124.182]2025年04月23日 01时43分26秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
web安全工具 御剑后台扫描&layer子域名挖掘机
2019-03-24
Laravel 直接返回404页面
2019-03-24
PHP 自定义错误与处理
2019-03-24
记一次内部系统渗透测试:小漏洞组合拳
2019-03-24
jquery-resizable使用
2019-03-24
常用元素操作的方法
2019-03-24
命名实体识别数据预处理
2019-03-25
事务消息应用场景、实现原理与项目实战(附全部源码)
2019-03-25
230. 二叉搜索树中第K小的元素
2019-03-25
Mac 重新安装操作系统后,如何删除容器中的其它卷宗
2019-03-25
分布式是登录机制是如何实现的。
2019-03-25
RabbitMQ入门【二】
2019-03-25
Node.js+Navicat for MySQL实现的简单增删查改
2019-03-25
Flutter出现Build failed with an exception。
2019-03-25
零基础学习 Vue3 教程 2021 年最新教程 免费视频教程(4 个视频)
2019-03-25
腹部MRI多脏器分割(多个类别的分割)
2023-01-23
解决 matplotlib 中文显示乱码的问题
2023-01-23
解决打开 json 文件中文乱码的问题
2023-01-23