用 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