用 python 解经典数学题


原题如下:

  有一个抢数游戏,其规则是两人轮流报数,每次可以报1 个,2 个,3 个,4个数,但不许不报也不许多报,如果第一个人报1,2 或1,2,3,第二个人接着往下报,然后第一个人接着往下报,以此类推,那么第一个人第一次应该报( )才可能稳抢到1024.

  1024,有点陡,我们先换一个小一点的数来分析:

  抢“30”游戏,两人从1开始轮流数数,最少数1个数,最多数3个数,谁数到30谁赢,怎么数?

分析(假设其中一个人是我,且我想赢):

 

 

  • 如果数到30就赢,且每次只能数1-3个数,那只需要数到26就可以了
  • 当我数到26,此时对方 加上1到3中的任何一个数都到不了30,反而只需要等对方数完后我再走一步就到30了,比如对方数2,就到28我再数个2就到30,对方数3,我数1就到30...

  怎样才能走到26呢,想一想:

  • 首先我们观察一下每次报的数:1、2、3,这三个数能不能两两组合成一个固定的数,我们发现,1+3=4,  2+2=4,所以这个固定的组合数就是 4 (自己去多写几个数来找找规律)

由此得方案:

  • 目标数 30 减去“最多数 3 个数”中的 3,再减 1 得 26
  • 如果 26 能被组合数 4 整除,则只需要对方先出,然后我每次出一个和对方相加和为 4 的数即可,最后我一定能数到 30

  但很明显此处的 26 不能被组合数 4 整除,所以:

  • 走第一步时一定要掌握主动权,将 26 钝化为可以被 4 整除的数,即 26 减去我第一步走的数后需要能被 4 整除。
  • 故我要走第一步,且必须数 2 。26 - 2=24,  得到的 24 能被 4 整除
  • 接下来只需要等对方出,(随便出1-3中哪个数),我方只需要出一个和对方数字相加为 4 的数即可胜利! (24/4=6 。即六轮后我就能数到30)

 

 答案:

  我先数,数2;接下来我只需要数一个和对方相加为 4 的数即可我赢、

接下来我们再来分析 1024 这道题:

方案如下:

1)  1024-4-1 = 1019  即只需要拿到1019即可赢

2)  组合数为:4+1 = 5

3)  1019 除不尽组合数 5

4)  故我先数,数4,    (1019-4=1015,这样1015才能被5整除)

5)  等对方数,然后我再数一个与对方的数和为5的数即可

 

 


 

接下来我们用 python 来实现:

 

以下代码直接复制即可运行(python3.7)

 1 import random
 2 
 3 def myFunc(n, stepper):
 4     """
 5     :参数 n: 目标数
 6     :参数 stepper: 步进范围(可以走几步的最大值)
 7     :返回值: (flag,first_num,total_stepper)
 8             第一个出还是第二个出:flag=1,第一个出;flag = 0第二个出
 9                 如果第一个出:第一次出多少 first_num
10                 如果第二个出:出的数总和为多少 total_stepper
11     """
12     total_stepper = stepper + 1  # 组合数
13     if n % total_stepper == 0:  #能整除的情况
14         print("目标数:{},步进范围:{},组合数:{}".format(n, stepper, total_stepper))
15         flag = 0   # 对方先出
16         return (flag, 0, total_stepper)
17     else:
18         v_num = n - stepper - 1  # 拿到v_num就一定能数到目标数
19         if v_num % total_stepper == 0:   # v_num能被组合数整除的情况
20             flag = 0    # 对方先出
21             print("目标数:{}, 步进范围:{}, 组合数:{}, 是否第一个出:{}".format(n, stepper, total_stepper, flag))
22             return (flag, 0, total_stepper)
23         else:
24             flag = 1   # 我方先出
25             first_num = v_num % total_stepper    # 我第一次数的数,这个数将v_num钝化为可以被组合数整除的数
26             print("目标数:{}, 步进范围:{}, 组合数:{}, 是否第一个出:{}, 出多少:{}".format(n, stepper, total_stepper, flag, first_num))
27             return (flag, first_num, total_stepper)
28 
29 print(myFunc(1024,4))

运行结果截图:

上面的代码每一行都有注释,结合着上面的分析来看就会很容易了。

最后的返回值为(是否先数,先数多少,组合数为多少)

 


 

  这个函数可不是只能算1024这一道题哦,以后遇到这一类型的题,我们都可以将我们的的目标数和步进范围输入函数,得到我们想要的答案。

  啦啦啦啦。。。python 在手,妈妈再也不用担心我的数学规律题了!

 

比如我们马上就可以试一试其他的组合:

例1:

  两个人数数,谁先数到2048谁就胜利,每次可以数1-6中的任一个数。问谁会赢,怎么数?

运行结果为:

答案为:第一个人赢。第一个人第一次数4,后面只需要数一个与对方的数和为 7 的数即可

 


 

 例2:

  两个人数数,谁先数到 2019 谁就胜利,每次可以数 1-18 中的任一个数。问谁会赢,怎么数?

运行结果为:

答案为:第一个人赢。第一个人第一次数5,后面只需要数一个与对方的数和为 19 的数即可

 


 

 例3:

  两个人数数,谁先数到 2020 谁就胜利,每次可以数 1-9 中的任一个数。问谁会赢,怎么数?

 

运行结果为:

答案为:第二个人赢。第二个人只需要数一个与第一个人数的数和为 10 的数即可赢

 


 

这样的结果是不是还不够友好,那接下来我们再用 python 来模拟一下整个数数过程吧。 

先来个温柔一点的数到 30 就可以了。

程序代码如下:

 1 import random
 2 
 3 def myFunc(n, stepper):
 4     total_stepper = stepper + 1  # 组合数
 5     if n % total_stepper == 0:  #能整除的情况
 6         flag = 0   # 对方先出
 7         return (flag, 0, total_stepper)
 8     else:
 9         v_num = n - stepper - 1  # 拿到v_num就一定能数到目标数
10         if v_num % total_stepper == 0:   # v_num能被组合数整除的情况
11             flag = 0    # 对方先出
12             return (flag, 0, total_stepper)
13         else:
14             flag = 1   # 我方先出
15             first_num = v_num % total_stepper    # 我第一次数的数,这个数将v_num钝化为可以被组合数整除的数
16             return (flag, first_num, total_stepper)
17 
18 
19 def myTest(n, stepper):
20     flag, first_num, total_stepper = myFunc(n, stepper)   #调用myFunc函数得到:是否先数、第一步数多少、组合数
21     print((flag, first_num, total_stepper))
22     i = 1   # 设定参照数
23     cnt = 0  # 数数容器
24     while True:
25         if flag == 1 and i == 1:
26             data = first_num
27             people = ""
28         elif flag == i % 2 and i != 1:
29             people = ""
30             data = total_stepper - data
31         else:
32             people = "码小易"
33             data = random.randint(1, total_stepper-1)
34         cnt += data
35 
36         print("{}第{}次出:{}".format(people, i, data))
37         if cnt == n:
38             break
39         i += 1
40 
41 
42 if __name__ == "__main__":
43     myTest(30, 3)

 

运行结果截图:

 

以上即将数数的全过程模拟得清清楚楚了,怎么样,现在来试试1024吧!

 


 

例4:

  数到1024赢,每次数1-4中的一个数:

 

  中间省略了若干行...

 

 


 

 

 经过以上两个程序,是不是觉得 python 已经把这道乃至于这一类磨人的数学题都梳理得服服帖帖的了呢,以后再遇到同样的数学难题,大家一定不要忘了用我们的 python 来实现,写几行代码不仅能解决一道绕半天都绕不出来的题,还能直接搞定一个类型的数学题。接下来就等着接收来自班里其他同学膜拜的眼神吧!

 

 

笔者会不定时的更新一些跟python相关又和数学相关的一些有趣的程序,喜欢就关注我吧。

 

 特别警示:本文为作者原创作品,禁止不经过本人同意就将其转载用于商业用途,否则将予以追究。出于学习分享转载请附上出处链接,谢谢!

 

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM