Reputation: 1549
I am doing a Project Euler question for programming practice in order to self-teach myself. I know perfectly well how to do the question mathematically, as well as how to do it programmatically.
However, I have to have come up with some insane code to do it; 100 nested loops and Python hilariously raises this error, and probably rightfully so, on 100 levels of indentation:
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
I have looked through google for solutions but this issue is so rare it has almost no literature on the subject and I could only find this other stack overflow question ( Python IndentationError: too many levels of indentation ) which I could not find much useful in for my question.
My question is - is there a way to take my solution and find some workaround or refactor it in a way that has it work? I am truly stumped.
Upvotes: 4
Views: 357
Reputation: 35079
To do this using exactly your algorithm (restricting each next number to one that can possibly fit in the required sum), you really do need recursion - but the true brute force method can be a one-liner:
sum(sum(i) == 100 for i in itertools.product(xrange(100), repeat=100))
Naturally, this will be a fair bit slower than a true refactoring of your algorithm (in fact, as mentioned in the comments, it turns out to be intractable).
Upvotes: 1
Reputation: 1421
The most effective solution is based on the idea of arithmetic carrying. You have lists of maximum values and steps, and also a list of current values. For each time you want to update those 100 variables, you do this:
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
When an IndexError is raised, you've finished looping (run out of 'digits' to carry into.)
Upvotes: 0
Reputation: 179452
A recursive solution should do nicely, though I'm certain there is an entirely different solution to the problem that doesn't require this kind of manipulation.
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)
Interestingly enough, if you memoize this function, it will actually have a reasonable running time (such is the power of dynamic programming). Have fun!
Upvotes: 5
Reputation: 226376
One way to avoid the indentation error is to put the loops in separate functions, each one nested only one level deep.
Alternatively, you could use recursion to call a function over and over again, each time with a smaller range and higher nesting level.
That being said, your algorithm will have an impossibly long running time no matter how you code it. You need a better algorithm :-)
Upvotes: 1