什么是约瑟夫环问题?
我们先了解一段历史。
Josephus是著名的犹太历史学家。
在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。
问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
简化问题:
简单来说,就是M个人围成一圈,第N个人从1开始报数,每次报到Q的人将被杀掉,下一个人接着从1开始报,再次报到Q,如此反复。
最后剩下的一个,就是幸存者。
分析:
解决这个经典的算法问题,有很多种解法,其中公式法是效率最高的。但我用的是单向循环链表。如果人数规模很小倒还好,但如果成千上万的规模,甚至更大。这个方法就会显得很笨。
解决这个问题,只需要三步。
准备工作:
你需要包含头文件,定义结构体。
#include
第一步:
初始化线性表
根据输入的总人数M,依次编号,循环创建链表。
// 初始化线性表
第二步:
从头节点遍历到指定的开始节点
// 链表遍历到开始位置
第三步:
固定步长循环删除节点
//循环删除节点
main():
当然你也可以不用像我这样,你自己简化喽!
int
可以发现,用循环链表解决约瑟夫环问题是比较傻瓜的,不需要什么奇技银巧,你只需要一五一十:
- 造节点
- 找节点
- 删节点
就完事儿了。
运行结果:
最终代码:
#include