Python algorithm to find total of some numbers - python

By starting at the top of the triangle below and moving to adjacent numbers on the row below, find the maximum total from top to bottom of the triangle below.
75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
This is Project Euler, Problem 18.
I got an answer as 1064. But they say it is wrong. Help me...in python 2.7
This is my code:
s='''Here the sequence'''
s=s.split("\n")
value=0
total=0
for x in range(len(s)):
y=s[x].split()
if (value+1)>x:
total+=int(y[value])
print int(y[value])
else:
if int(y[value])>int(y[value+1]):
total+=int(y[value])
print int(y[value])
else:
total+=int(y[value+1])
print int(y[value+1])
value+=1
print "Total:::%d"%total

The problem with your algorithm is that you only explore a single path through the triangle: At each "junction", you always select the higher value and proceed down that path. But this "greedy" algorithm does not always work. Consider this example:
1 Yours: (1) Best: (1)
1 2 1 (2) (1) 2
9 1 1 9 (1) 1 (9) 1 1
When presented with the choice of 1 or 2, you select 2 and go down the right path, missing out the 9. Instead, you have to consider all the paths. You can do this in a "dynamic programming" kind of fashion, where you store the highest-possible value that can be reached in each cell and then just add them up. You can do this top-down or bottom-up, and then just select the highest value in the final row.
Example (bottom-up): In each step, add the maximum of the two adjacent lower cells to the cell above.
5 5 5 5 5 ==> 5+17
2 4 2 4 2 4 ==> 2+11 4+13 ==> 13 17
3 5 7 ==> 3+5 5+6 7+6 ==> 8 11 13
1 5 6 2
Implementing this idea in an algorithm is left as an excercise to the reader. ;-)

You have a greedy algorithm, which appends the largest adjacent number at every iteration. It produces a suboptimal solution. Simple explanation - consider just a triangle that consists of three top rows. Your solution will be 75 + 95 + 47 = 217. While the optimal solution in this case is 75 + 64 + 82 = 221. How to solve this? I would recommend designing a dynamic programming algorithm.

Related

graph_tool: how to avoid that all_circuits function block my script

I'm learning python and I'm doing some experiment with the module graph_tool.
Since the function all_circuits could take a long time to calculate all the cycles, is there a way to stop the function (for example after "X" seconds or after the iterator reaches a certain size) and continue the execution of the script?
Thanks
This is quite simple, actually. The function all_circuits() returns an iterator over all circuits. Therefore, if you want to stop early, all you need is to break the iterations:
g = collection.ns["football"]
for i, c in enumerate(all_circuits(g)):
if i > 10:
print(c)
break
which prints
[ 0 1 25 24 11 10 5 4 9 8 7 6 2 3 26 12 13 15
14 38 18 19 29 30 35 34 31 32 21 20 17 16 23 22 47 46
49 48 44 45 33 37 36 43 42 57 56 27 62 61 54 39 60 59
58 63 64 100 99 89 88 83 53 52 40 41 67 68 50 28 69 70
65 66 75 76 95 87 86 80 79 55 94 82 81 72 74 73 110 114
104 93]
and stops.

How to create 1-100 in 10 rows? [duplicate]

This question already has answers here:
How to right-align numeric data?
(5 answers)
Closed 5 years ago.
I'm trying to get the following exercise:
"Write a program containing a pair of neste while loops that displays the integer values 1-100, ten numbers per row, with the columns alignes as below.
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
So far I've come up with this:
lijst = list(range(1, 101))
i = 0
while i < 100:
print(lijst[i],"\t", end=" ".format(">"))
i = i+1
if i % 10 == 0:
print("")
Although it produces the things I need, the tabs aren't working. whenever I try to add spaces instead of a tab, things move way too much on the second and further rows.
Furthermore I can't seem to find out why the .format(">") doesn't work. I've tried to apply .format(">3") but that didn't do anything at all.
You can use the {:>5d} format style to right align integers 5 spaces
lijst = list(range(1, 101))
i = 0
while i < 100:
print("{:>5d}".format(lijst[i]), end=" ")
i = i+1
if i % 10 == 0:
print("")
Output:
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100

Last cell in a column dataframe from excel using pandas

I just had a quick question. How would one go about getting the last cell value of an excel spreadsheet when working with it as a dataframe using pandas, for every single different column. I'm having quite some difficulty with this, I know the index can be found with len(), but I can't quite wrap my finger around it. Thank you any help would be greatly appreciated.
If you want the last cell of a dataframe meaning the most bottom right cell, then you can use .iloc:
df = pd.DataFrame(np.arange(1,101).reshape((10,-1)))
df
Output:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9 10
1 11 12 13 14 15 16 17 18 19 20
2 21 22 23 24 25 26 27 28 29 30
3 31 32 33 34 35 36 37 38 39 40
4 41 42 43 44 45 46 47 48 49 50
5 51 52 53 54 55 56 57 58 59 60
6 61 62 63 64 65 66 67 68 69 70
7 71 72 73 74 75 76 77 78 79 80
8 81 82 83 84 85 86 87 88 89 90
9 91 92 93 94 95 96 97 98 99 100
Use .iloc with -1 index selection on both rows and columns.
df.iloc[-1,-1]
Output:
100
DataFrame.head(n) gets the top n results from the dataframe. DataFrame.tail(n) gets the bottom n results from the dataframe.
If your dataframe is named df, you could use df.tail(1) to get the last row of the dataframe. The returned value is also a dataframe.

Project Euler #18 in Python- Beginner

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.
3
7 4
2 4 6
8 5 9 3
That is, 3 + 7 + 4 + 9 = 23.
Find the maximum total from top to bottom of the triangle below:
75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
NOTE: As there are only 16384 routes, it is possible to solve this problem by trying every route. However, Problem 67, is the same challenge with a triangle containing one-hundred rows; it cannot be solved by brute force, and requires a clever method! ;o)
My code is a bit haywire
a="75, 95 64, 17 47 82, 18 35 87 10, 20 04 82 47 65, 19 01 23 75 03 34, 88 02 77 73 07 63 67, 99 65 04 28 06 16 70 92, 41 41 26 56 83 40 80 70 33, 41 48 72 33 47 32 37 16 94 29, 53 71 44 65 25 43 91 52 97 51 14, 70 11 33 28 77 73 17 78 39 68 17 57, 91 71 52 38 17 14 91 43 58 50 27 29 48, 63 66 04 68 89 53 67 30 73 16 69 87 40 31, 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23"
b=a.split(", ")
d=[]
ans=0
for x in range(len(b)):
b[x]= b[x].split(" ")
c= [int(i) for i in b[x]]
d.append(c)
index= d[0].index(max(d[0]))
print index
for y in range(len(d)):
ans+= d[y][index]
if y+1==len(d):
break
else:
index= d[y+1].index(max(d[y+1][index], d[y+1][index+1]))
print ans
So I'm getting 1063 as the answer whereas the actual answer is 1074. I guess my approach is right but there's some bug I'm still not able to figure out.
Your approach is incorrect. You can't just do a greedy algorithm. Consider the example:
3
7 4
2 4 6
8 5 9 500
Clearly:
3 + 7 + 4 + 9 = 23 < 500 + (other terms here)
Yet you follow this algorithm.
However if the triangle were just:
3
7 4
The greedy approach works, in other words, we need to reduce the problem to a kind of "3 number" triangle. So, assume the path you follow gets to 6, what choice should be made? Go to 500. (What happens if the apath goes to 4? What about 2?)
How can we use these results to make a smaller triangle?
It looks like you always choose the larger number (of left and right) in the next line (This is called a greedy algorithm.) But maybe choosing the smaller number first, you could choose larger numbers in the subsequent lines. (And indeed, by doing so, 1074 can be achieved.)
The hints in the comments are useful:
A backtrack approach would give the correct result.
A dynamic programming approach would give the correct result, and it's faster than the backtrack, thus it can work for problem 67 as well.
Small remark on your code.
The maximum sum in this triangle is indeed 1074. Your numbers are correct, just change your for-loop code from
for i,cell in enumerate(line):
newline.append(int(cell)+max(map(int,topline[max([0,i-1]):min([len(line),i+2])])))
to
for i,cell in enumerate(line):
newline.append(int(cell)+max(map(int,topline[max([0,i-1]):min([len(line),i+1])])))
(The "1" instead of "2")
Kindly
You can reach each cell only from the adjacent (at most) three cells on the top line, and the most favorable will be the one with the highest number among these, you don't need to keep track of the others.
I put an example of the code. This works for the pyramid aligned to the left as in your question (the original problem is with a centered pyramid, but at least I don't completely spoil the problem). Max total for my case is 1116:
d="""
75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
"""
ll=[line.split() for line in d.split('\n')][1:-1]
topline=ll[0]
for line in ll[1:]:
newline=[]
for i,cell in enumerate(line):
newline.append(int(cell)+max(map(int,topline[max([0,i-1]):min([len(line),i+2])])))
topline=newline
print newline
print "final results is %i"%max(newline)
I thought about this problem all day and night. Here is my solution:
# Maximum path sum I
import time
def e18():
start = time.time()
f=open("num_triangle.txt")
summ=[75]
for s in f:
slst=s.split()
lst=[int(item) for item in slst]
for i in range(len(lst)):
if i==0:
lst[i]+=summ[i]
elif i==len(lst)-1:
lst[i]+=summ[i-1]
elif (lst[i]+summ[i-1])>(lst[i]+summ[i]):
lst[i]+=summ[i-1]
else:
lst[i]+=summ[i]
summ=lst
end = time.time() - start
print("Runtime =", end)
f.close()
return max(summ)
print(e18()) #1074
P.S. num_triangle.txt is without first string '75'

Python: I am unable to comprehend the concept of a For Loop, apparently

I've got a list of 400 numbers, and i want to but them in a 20x20 grid using Python.
I've made a "2d array" (not really because Python doesn't support them, I've had to use a list of lists.)
When i try to loop through and assign each subsequnt item to the next box in the grid, it fails. i end up assinging the last item in the list to every box.
Here's the code:
numbers = "08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91 22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80 24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50 32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70 67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21 24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72 21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95 78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92 16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57 86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58 19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40 04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66 88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69 04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36 20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16 20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54 01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48"
grid = [[0 for col in range(20)] for row in range(20)]
for x in range(0, 1200, 3):
y = x + 2
a = numbers[x:y]
for i in range(20):
for j in range(20):
grid[i][j] = a
print(grid)
I can see why it's going wrong: the two loops that generate the list coordinates are inside the loop that gets each items from the list, so each time they run the value they are assigning doesn't change.
Therefore I guess seeing as they don't work in the loop, they need to be out of it.
The problem is that I can't work out where exactly.
Anyone give me a hand?
This is the sort of thing that list comprehensions are good for.
nums = iter(numbers.split())
grid = [[next(nums) for col in range(20)] for row in range(20)]
Alternatively, as a for loop:
grid = [[0]*20 for row in range(20)]
nums = iter(numbers.split())
for i in xrange(20):
for j in xrange(20):
grid[i][j] = next(nums)
I'm not recommending that you do this, but the way to do it if you don't just want to split the list and then call next on its iterator is to write a generator to parse the list the way that you were and then call next on that. I point this out because there are situations where builtins wont do it for you so you should see the pattern (not Design Pattern, just pattern for the pedantic):
def items(numbers):
for x in range(0, len(numbers), 3):
yield numbers[x:x+2]
nums = items(numbers)
for i in xrange(20):
for j in xrange(20):
grid[i][j] = next(nums)
This lets you step through the two loops in parallel.
Another alternative is to use the grouper idiom:
nums = iter(numbers.split())
grid = zip(*[nums]*20)
Note that this makes a list of tuples, not a list of lists.
If you need a list of lists, then
grid = map(list,zip(*[nums]*20))
Your for loop confusion stems from having more loops than you need.
Instead, one approach is to start by looping over your grid squares and then figuring out the needed offset into your list of numbers:
for i in range(20):
for j in range(20):
offset = i*20*3 + j*3
grid[i][j] = numbers[offset:offset+2]
In this case, the offset has a few constants. i is the row, so for each row you need to skip over a row's worth of characters (60) in your list. j is the column index; each column is 3 characters wide.
You could, of course, do this operation in reverse. In that case, you would loop over your list of numbers and then figure out to which grid square it belongs. It works very similarly, except you'd be using division and modulo arithmetic instead of multiplication in the offset above.
Hopefully this provides some insight into how to use for loops to work with multiple objects and multiple dimensions.

Categories

Resources