摘要
主要是之前一直不知道约瑟夫环的dp解法,这里和大家分享一下。本文用三种方法给大家呈现本题。
最后一条毛毛虫
题目描述
小D的花园里养了 n 条毛毛虫,每条毛毛虫都有自己独有的编号(从 1 到 n )。
一开始,所有的毛毛虫都开开心心地生活在花园里,享受着食物和阳光。
直到某一天,额……它们知道自己肯定会被吃掉,所以就开始玩一个游戏,来决定被吃的顺序。游戏的方法是这样的:
所有毛毛虫按照编号顺序从 11 到 n 顺时针围成一个环,然后从 1 号毛毛虫开始顺时针依次报数,报到数字 m 的毛毛虫就出环被吃,下一条毛毛虫继续从 1 开始顺时针报数……直到所有毛毛虫都出环被吃。
那么,最后一条被吃的毛毛虫的编号是多少呢?
时间限制:1000ms,内存限制:65536KB
输入
两个正整数 n,m ,意义如题所示。
输入数据保证: 1≤n,m≤3000。
输出
一个正整数,代表最后一条被吃的毛毛虫的编号。
输入样例
1 | 5 3 |
输出样例
1 | 4 |
样例解释
毛毛虫被吃的顺序依次为:3、1、5、2、4 。
题目来源
分析
(1) 首先很显然最简单的约瑟夫环问题,肯定用最容易理解的方法就是循环链表了。通过指针遍历、删除来完成每次的报数和出局环节,最后只剩一条毛毛虫时,就结束就可以了。虽然非常容易理解,但是代码比较长,时间花费也比较高(和后面介绍的方法相比),但本题的限制还是可以随便AC的。代码如下:
1 |
|
(2) 第二第三种方法本质一样,只是实现方式有所区别。都是通过数学方法进行一些推导得到的。首先我们假设编号从0开始,最后求出的答案再加1就好了,所以可以知道在第一次中,肯定是叫到(m-1)%n的会出局,那么第一次出局的下一个肯定就是m%n了,如果把他当作0号,那剩下的n-1个人又组成了一个新的约瑟夫环,此时出局的就是(m-1)%(n-1),但是因为现在的0号并不是0号,而是m%n号,所以我们得到的胜利者还要加回去,也就是((m-1)%(n-1)+m%n)%n,如果我们把第n-1次胜利者看作f(n-1)的话,那第n次的胜利者肯定就是(f(n-1)+m%n)%n,那对于第三次开始叫号也就是同样的道理,胜利者编号就为((f(n-2)+m%(n-1))%(n-1)+m%n)%n,可以看出是有规律的,我们用式子写出来就是f(n)=(f(n-1)+m%n)%n,f(n-1)=(f(n-2)+m%(n-1))%(n-1),化简得到就一个式子f(n)=(f(n-1)+m)%n,对于n∈[0,n]都是成立的。那么我们就可以写递归代码了,如下:
1 |
|
(3) 但是这样递归,其实多了很多重复计算的步骤,是可以优化的,即DP,所以转移方程也就是上文提到的f(n)=(f(n-1)+m)%n
,甚至不需要数组来存,直接就能出来,代码如下:
1 |
|
结语
有谬误敬请指出,敬请不吝赐教