2012-09-26 17 views
4

我正在做一個Project Euler編程實踐的問題,以便自我教導自己。我非常清楚如何在數學上做這個問題,以及如何以編程的方式做到這一點。Python IndentationError - 如何重構?

但是,我必須想出一些瘋狂的代碼來做到這一點; 100個嵌套循環和Python歡快提出了這個錯誤,而且很可能是理所當然的,在100個級別的縮進:

IndentationError: too many levels of indentation 



tally = 0 
ceiling = 100 
for integer_1 in range(0, 100, 1): 
    for integer_2 in range(0, 100 - integer_1, 2): 
     for integer_3 in range(0, 100 - integer_1 - integer_2, 3): 
      for integer_4 .... 
       for integer_5 .... 
        etc. 
         etc. 
          all the way to integer_100 

我已經通過谷歌尋找解決方案,但這個問題是如此罕見,它幾乎沒有文學的主題和我只能找到這個其他堆棧溢出問題(Python IndentationError: too many levels of indentation),我無法找到對我的問題很有用的問題。

我的問題是 - 有沒有辦法讓我的解決方案,並找到一些解決方法或重構它的方式,它的工作?我真的很難過。

編輯:

由於nneonneo的回答,我是能夠解決的問題。我的代碼僅供將來參考,用於尋找正確重構代碼的方法。

from time import time 
t = time() 
count_rec_dict = {} 

# for finding ways to sum to 100 
def count_rec(cursum, level): 
    global count_rec_dict 

    # 99 is the last integer that we could be using, 
    # so prevent the algorithm from going further. 
    if level == 99: 
     if cursum == 100: 
      return 1 
     else: 
      return 0 

    res = 0 

    for i in xrange(0, 101-cursum, level+1): 

     # fetch branch value from the dictionary 
     if (cursum+i, level+1) in count_rec_dict: 
      res += count_rec_dict[(cursum+i, level+1)] 

     # add branch value to the dictionary 
     else: 
      count_rec_dict[(cursum+i, level+1)] = count_rec(cursum+i, level+1) 
      res += count_rec_dict[(cursum+i, level+1)]   

    return res} 

print count_rec(0, 0) 
print time() - t 

它在我的電腦上以驚人的0.041秒運行。哇!!!!!今天我學到了一些新東西!

+0

射擊 - 對不起,我在範圍內有一個錯誤。現在修復 – nebffa

+2

只需要說,如果你有100個嵌套循環,那就應該有更好的方法... – Claudiu

+1

這看起來很蠻橫,而且無論哪個歐拉問題,我敢打賭有一個更聰明的方法來做它。很多這些問題都基於數學見解。 – wim

回答

5

遞歸解決方案應該做的很好,但我確定有一個完全不同的解決方案來解決不需要這種操作的問題。

def count_rec(cursum, level): 
    if level == 100: 
     return 1 
    res = 0 
    for i in xrange(0, 100-cursum, level+1): 
     res += count_rec(cursum+i, level+1) 
    return res 

print count_rec(0, 0) 

有趣的是,如果你memoize的這個功能,它實際上有一個合理的運行時間(例如是動態規劃的功率)。玩的開心!

+0

示例:對於範圍內的整數_5(0,100-整數-1-整數2-整數_3_整數_4,5) 。所有循環都遵循這種模式。 – nebffa

+0

但最裏面的循環是什麼? – nneonneo

+0

一個簡單的「理貨+ = 1」。僅此而已 - 只需要統計整個系統有多少次結束。 – nebffa

1

避免縮進錯誤的一種方法是將循環放在單獨的函數中,每個函數只嵌套一層深度。

或者,您可以使用遞歸來反覆調用函數,每次使用更小的範圍和更高的嵌套級別。

這就是說,你的算法將有一個不可思議的長時間運行時間,不管你如何編碼它。你需要一個更好的算法:-)

+0

我不太清楚實際需要運行多久 - 我已經調整了範圍的上限以縮短長時間運行時間。也許你可能是對的,我可能需要找到另一種方法: - )。但是,在這種情況下,我沒有看到如何使用遞歸,但仍然沒有使用蒙版縮進的問題。你能提供一個簡短的僞代碼示例嗎? – nebffa

+0

有趣的事實:作爲一個遞歸的memoized函數,由於(隱式)動態編程,它實際上沒有不可能長的運行時間。 – nneonneo

1

要完全使用你的算法(將每個下一個數字限制爲可能適合所需總和的數字),你確實需要遞歸 - 但真正的蠻力方法可以一個班輪:

sum(sum(i) == 100 for i in itertools.product(xrange(100), repeat=100)) 

當然,這將是比你的算法,真正的重構慢公平位(其實,作爲在評論中提到,它原來是棘手的)。

+0

這需要比宇宙的運行時間更長的時間 - 這就是爲什麼我不能使用強力方法。 – nebffa

+0

@nebffa我不認爲「長於宇宙的年齡」是完全正確的;不應該超過比如說幾個星期。 – lvc

+3

@lvc:不,100 ** 100皮秒比當前宇宙年齡長很多,這就是你在這裏做的迭代次數。 – nneonneo

0

最有效的解決方案是基於算術運算的思想。 您有最大值和步驟列表, 以及當前值列表。對於要更新的​​100個變量每一次,你這樣做:

inc_index = -1 
currentvalue[inc_index] += stepval[inc_index] 
# I use >= rather than > here to replicate range()s behaviour that range(0,100) generates numbers from 0 to 99. 
while currentvalue[inc_index] >= maxval[inc_index]: 
    currentvalue[inc_index] = 0 
    inc_index -= 1 
    currentvalue[inc_index] += stepval[inc_index] 
# now regenerate maxes for all subordinate indices 
while inc_index < -1: 
    maxval[inc_index + 1] = 100 - sum (currentvalue[:inc_index]) 
    inc_index += 1 

當IndexError升高時,你已經完成循環(用完的「數字」能夠輕鬆地進入)