NO.1 嘗試優化a+b+c=1000(abc爲自然數),且a^2+b^2=c^2,如何求出a,b,c 的問題

第一條,枚舉法,那就是用一個數一個數去試試,假設a=0,b=0,這時候c=1000,用循環一個一個的試
,貼一下這個笨拙的代碼,爲了驗證運行消耗的時間引入了time模塊

import time
start_time=time.time()
for a in range(1,1001):
    for b in range(1, 1001):
        for c in range(0, 1001):
            if a+b+c==1000 and a**2+b**2==c**2:
                print(a,b,c)
end_time=time.time()
print('time:%d'%(end_time-start_time))
print('結束')

運算結果如下:

200 375 425
375 200 425
time:150
結束


程序算完一共用了150秒,這個時候我的CPU佔用率甚至到達了96%
那現在我們來試試當abc的範圍擴大到10000時需要多少時間

import time
start_time=time.time()
for a in range(1,10001):
    for b in range(1, 10001):
        for c in range(1, 10001):
            if a+b+c==10000 and a**2+b**2==c**2:
                print(a,b,c)
end_time=time.time()
print('time:%d'%(end_time-start_time))
print('結束')

而這個10000的計算量在我運行超過1個小時後還未計算出結果我就放棄這種計算方式,這顯然不是我想要的
這個方案解決這個問題是可以,但一旦這個範圍過大,運算時間就會爆掉,所以我們需要更快時間並且更節省內存的方法
現在我做一個小小的優化,當a,b的循環語句後加入一個 c=1000-a-b 來替換掉原來的 for c in range(0, 1001) ,因爲本身abc三者的範圍關係是確定的,而這裏我們我們不需要再多加一個c循環來計算c的值,再修改後運行速度就得到了明顯的提升

import time
start_time=time.time()
for a in range(1,1001):
    for b in range(1, 1001):
        c=1000-a-b
        if a**2+b**2==c**2:
            print(a,b,c)
end_time=time.time()
print('time:%d'%(end_time-start_time))
print('結束')

運行結果如下:

200 375 425
375 200 425
time:1
結束


可以看到運行速度由原來的150秒提升到了1秒,而我們來看看範圍擴大到10000的情況

import time
start_time=time.time()
for a in range(1,10001):
    for b in range(1, 10001):
        c=10000-a-b
        if a**2+b**2==c**2:
            print(a,b,c)
end_time=time.time()
print('time:%d'%(end_time-start_time))
print('結束')

運行結果如下:

2000 3750 4250
3750 2000 4250
time:177
結束


在引入第二次結果後我們可以看出一個問題,那就是解決同一個問題的方法有多種,第一次寫的程序與第二次寫的程序是有差別的,算法與算法之間有着效率的差別,然而即使是第二種方法在處理超過1W的範圍後計算速度也十分緩慢,令人難以忍受,所以我嘗試繼續來優化
在第二次方法中:
c=10000-a-b
if a+b+c==1000 and a**2+b**2==c**2
這兩段實際可以可以糅合在一段,我們不需要重新設立變量c,那麼直接在判斷語句中計算(1000-a-b)的值會怎麼樣呢?

for a in range(1,1001):
    for b in range(1,1001):
        if a**2+b**2==(1000-a-b)**2:
            print(a,b,1000-a-b)

這裏計算出來的結果是

200 375 425
375 200 425
time:1
結束


咦,似乎看不出與上一段的計算時間的區別,那我們再試試把範圍提升到10000

這裏計算出來的結果是

2000 3750 4250
3750 2000 4250
time:154
結束


在這裏可以看出來這一次的計算時間比上一次似乎有所提高,但這還是不能滿足我期望思維快速計算的要求,再又經過思考後,現在我們回到題目,首先是兩個條件:
1、a+b+c=1000
2、a^2+b^2=c^2
針對已知條件1,2,可通過a + b + c = 1000得出a^2+b^2+c^2+2ab+2ac+2bc=1000000,把a^2+b^2=c^2和c=1000-a-b代入後化簡得出公式1000(a+b)-2ab=500000
然後用新的公式帶入原來的腳本中

for a in range(1,1001):
    for b in range(1,1001):
        if 1000*(a+b) - 2*a*b == 500000:
            print(a,b,1000-a-b)

這裏1000的計算時間還是看不出差異,我直接計算範圍爲10000的結果

這裏計算出來的結果是

2000 3750 4250
3750 2000 4250
time:40
結束


現在可以看出這個算法較之前的工作時間提升了3分之2,但對於十萬量的數據計算時間依然還是漫長,我覺得這個速度我依然不滿意,而在讀過算法圖解後我明白了有一種很簡單的算法叫2分法,然後我將這種方法嘗試寫入我的程序中
再次思考問題
a顯然不等於b,如果a等於b,則c不能爲整數,爲了避免重複,比如a和b交換位置的情況,不妨考慮a < b < c,則可以知道a<1000/3, c>1000/3, b<1000/2;

import time
start_time=time.time()
a_range = 10000 // 3
b_range = 10000 // 2
for a in range(1, a_range):
    b_high =b_range
    b_low = a + 1
    while True:
        b = (b_low + b_high) // 2
        c = 10000 - a - b
        if a ** 2 + b ** 2 == c ** 2:
            print("a=%d, b=%d, c=%d" % (a, b, c))
            break
        elif a ** 2 + b ** 2 > c ** 2:
            b_high = b
        elif a ** 2 + b ** 2 < c ** 2:
            b_low = b + 1
        if b_low == b_high :
            break
end_time=time.time()
print('time:%d'%(end_time-start_time))
print('結束')

在這裏,10000運行的時間還是0,而100000的運行結果如下:


a=20000, b=37500, c=42500
a=21875, b=36000, c=42125
time:2
結束

一百萬範圍的結果爲:

a=200000, b=375000, c=425000
a=218750, b=360000, c=421250
time:26
結束

這次的結果爲26秒,這個計算方式是我能想到最簡潔的,希望有更多的朋友給我提供更多更好的思路和方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章