题目
猴群一共有 n 只猴子,现在它们要选出大王,具体方法是:所有猴子按位置 1- n 围坐成一圈,从第 1 个位置开始按顺序 1-m 报数,“1、2、3……m – 1、m”。报到 m 的猴子就要离开此圈,它下一个位置重新 1-m 报数。这样依次下来,直到只剩下最后一只猴子,则该猴子为大王。
你作为一只聪明的猴子,为了成为大王,最开始要坐在哪个位置呢?
输入
一行两个正整数,即 n、m。
输出
一个整数,即你最开始坐的位置(猴王位置)。
有的人是第一次见这种题目,这题其实是经典的约瑟夫问题。故事背景什么的网上都可以搜到,这里就不再赘述。下面来讲解题方法。
示例输入 $ 10$ $ 3$
输出$ 4$
1.模拟法
由题意来进行模拟,定义一个变量为报的数,一个变量为报到的人,每次将报到3的人退出。在python里可以开一个列表,然后遍历列表,将报到3的人退出列表,如果遍历列表长度大于1,就再次遍历,直到列表里只剩下一个数(大概是这样,python也不是很会,差不多)。
这种能过数据较小的点,在题目里显然是不能拿到满分的。
2.公式
我们将每一次报数的顺序排出来,每有一个人报到3我们就重新开始报数,我们将每一次报数的顺序写出来,如下图:
这里我们将第一个报到的人的下标记作0,方便后面的计算。
我们看看全局可以看到每一次下一轮开始报数的人一定是这一轮报到的人的下一个,这很显然是显而易见的。应该没问题吧。
那么我们可以从这一行所报的数字的位置而推断出上一行该数字的位置。就第10行为例好了,这个数是第10行的第一个数,那么就是上一行的报到的人的下一个,那么就应该是在第9行的第3个报到的人的后面,就是第九行第4个人,下标为3。
那么新的问题来了 有两个数按这个顺序排列 $10,4,10,4,10…,10,4$;那么第4个数第一次出现是在第1个数的位置还是在第2个数的位置呢?很明显除以数的个数取余(模)一下就可以找到对应的关系了,这里通过下标来表示,置于下表为什么要从零开始下面还会再讲,那么我们通过下标$3%2$即可获得它在第9层的下标,所以4在第9行第一次出现是在2这个位置,下标为1。知道了这个就可以让我们继续推它在上一层的位置了。推到第一层之后那么猴王在第一层的位置就确定了。
继续按照这样子推下去,4在第9层第一次出现是第2个数那么他在第8层就应该是$3+2=5$,第5个数,第8层一共有3个数,所以通过他的下标4%3=1即可获取他在第8层的下标;
如果下标从1开始的话基本步骤还是一样,只是当下标%数的个数时当余数为0时要进行特殊处理,第一次在0出现那么一共有n个数,所以第一次出现是在第n个数,由此看出下标从1开始需要进行特判,所以一般不采用这种方法。而如果下标从0开始就不会有这种情况,只需要最后求出最后一个人在第一轮的下标时加1就能获得该数。
所以说我们一直从下往上递推(指循环)就可以了,若有n个数,报到i的人退出,循环从下往上,将n-1层看成第2层,因为第n-1层有2个数方便计算,将第1层堪称第n层。因此层数=数的个数然后循环从第2层开始,计算公式:数在下一层的下标=(数在这一层的下标+i)%层数;
猴王在第1层下标为0,套入公式即可算出它在第n层也就是第一轮的下标,那么他的位置也就是下标加1。答案就出来了。
代码:
n,m=map(int,input().split()) #n表示数的总个数,m为报到m的猴子出圈
ans=0;
for i in range(2,n+1,1): # 从下往上每一层递推
ans=(ans+m)%i; #在这一层的下标=(上一层的下标+m)%这一层不重复的数的个数
print(ans+1) #答案的数字为下标加1,看图更加方便理解
(第一版)待完善,等下次有时间再说。