Related
I have this method which returns the max sum of the path from top left to bottom right (can move only to the right or bottom).
def max_path(grid):
N = len(grid)
M = len(grid[0])
sum = [[0 for i in range(M + 1)] for i in range(N + 1)]
for i in range(1, N + 1):
for j in range(1, M + 1):
sum[i][j] = (max(sum[i - 1][j], sum[i][j - 1]) + grid[i - 1][j - 1])
return sum[N][M]
matrix = [[1, 2, 3], [3, 4, 5]]
print(max_path(matrix))
output : 1 + 3 + 4 + 5 = 13
But what I want to get is also the coordinates of the points of the path:
[(0,0) (1,0) (1,1) (1,2)]
You can try the below code to get your job done.
from itertools import permutations, product
def get_max_sum(table):
height, width = len(table), len(table[0])
sum_, *pos = max((sum(table[x][y] for x, y in zip(*pairs)), *zip(*pairs))
for pairs in product(
permutations(range(height)),
([*range(i, width), *range(i)] for i in range(width))))
return (sum_, *sorted(pos))
sum_, *pos = get_max_sum(
[[1, 2, 3],
[2, 3, 5],
[4, 9, 16]]
)
Output:
20 #maximum sum
(0, 1) (1, 0) (2, 2) #co -ordinates
The variable sum after the nested-for loops (as written in your code) is
[0, 0, 0, 0],
[0, 1, 3, 6],
[0, 4, 8, 13]
You can work out the coordinates of the max sum by having a initial "pointer" at the bottom right corner (i=1, j =2, ignoring the zeros), and comparing the values that is on the top (i=0, i=2) and on the left (i=1, j=1). Since 8 is larger than 6, we move the "pointer" to the left, and now i=1, j=1.
4 is larger than 3, so we move the pointer to 4 (i=1, j=0)
1 is larger than 0, so we move the pointer to 1 (i=0, j=0)
A basic (untested) implementation of the algorithm is as follows:
def max_path(grid):
N = len(grid)
M = len(grid[0])
sum = [[0 for i in range(M + 1)] for i in range(N + 1)]
for i in range(1, N + 1):
for j in range(1, M + 1):
sum[i][j] = (max(sum[i - 1][j], sum[i][j - 1]) + grid[i - 1][j - 1])
j = M
i = N
path = []
while i > 0 and j > 0:
path.append((i-1,j-1))
if sum[i-1][j] <= sum[i][j-1]:
j -= 1
else:
i -= 1
path.reverse()
return sum[N][M],path
matrix = [[1, 2, 3], [3, 4, 5]]
print(max_path(matrix))
I need to make a checkerboard using only 1 and 0's by using lists to make a grid. I have created a code that creates an 8 by 8 grid of 0's. Then I attempt to use a nested for loop to fill it in, what am I doing wrong?
board = []
def print_board(board):
for i in range(8):
board.append([0]*8)
for i in range(len(board)):
for j in range(len(board[i])):
if i == 0 or i == 2 or i == 4 or i == 6 and j == 1 or j == 3 or j==5 or j==7:
board[i][j] = 1
elif i == 1 or i ==3 or i == 5 or i == 7 and j == 0 or j == 2 or j==4 or j==6:
board[i][j] = 1
for i in range(len(board)):
print(board[i])
print_board(board)
Why are the if and elif statements not working?
To make a checkerboard, a simple strategy is to check the parity of rows/cols.
If identical, set to 1 (or 0), if different, set the other way around.
This can be achieved with a simple list comprehension:
def board(n=8):
return [[int(i%2==j%2) for i in range(n)] # converting True to 1 directly
for j in range(n)]
output:
board(8)
[[1, 0, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1],
[1, 0, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 1]]
board(5)
[[1, 0, 1, 0, 1],
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 1],
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 1]]
The reason that the code doesn't work is that the interpreter treats:
i == 0 or i == 2 or i == 4 or i == 6 and j == 1 or j == 3 or j==5 or j==7:
as
((i == 0 or i == 2 or i == 4 or i == 6) and j == 1) or j == 3 or j==5 or j==7:
i.e. it starts from the left and evaluates each operator one by one.
You can correct your code by replacing:
if i == 0 or i == 2 or i == 4 or i == 6 and j == 1 or j == 3 or j==5 or j==7:
board[i][j] = 1
elif i == 1 or i ==3 or i == 5 or i == 7 and j == 0 or j == 2 or j==4 or j==6:
board[i][j] = 1
With:
if (i == 0 or i == 2 or i == 4 or i == 6) and (j == 1 or j == 3 or j==5 or j==7):
board[i][j] = 1
elif (i == 1 or i ==3 or i == 5 or i == 7) and (j == 0 or j == 2 or j==4 or j==6):
board[i][j] = 1
Or replace it with this condition
if i % 2 == 0 and j % 2 != 0:
board[i][j] = 1
elif i % 2 != 0 and j % 2 == 0:
board[i][j] = 1
A better way to do this would be:
board = []
for i in range(0, 8):
board.append([])
for j in range(0, 8):
board[i].append((i + j) % 2)
print(board[-1])
Or
def board(k=8):
return [[int(i%2!=j%2) for i in range(k)] for j in range(k)]
I need to return the vector solution x of Ux = b for an upper triangular matrix U and vector b using back substitution, but I'm unable to actually access an element of the matrix U.
def BackSub(U, b):
n = len(U)
x = [0 for i in range(n)]
for i in range(n - 1, -1, -1):
s = 0
for j in range(n - 1, i, -1):
s += (U[i][j])*b[j]
b[i] = (b[i] - s)/(U[i][i])
return b
b = [5, 6, 3, 2]
U = [[ 1, 2, 1, 0],
[ 0, 3, -5, 9],
[ 0, 0, 0.5, 1],
[ 0, 0, 0, 7]]
N = GaussElim(U, b)
x = BackSub(N, b)
It returns
TypeError: 'float' object is not subscriptable for U[i][i]
The GaussElim function is this
import numpy as np
def GaussElim(A, b):
n = len(b) #n is matrix size
#Elimination phase
for k in range(0 , n - 1): #k is matrix row
for i in range(k + 1, n): #i is matrix col
if A[i][k] != 0:
factor = A[i][k]/ A[k][k]
A[i][k + 1 : n] = A[i][k + 1 : n] - np.multiply(factor, A[k][k + 1 : n])
b[i] = b[i] - np.multiply(factor, b[k])
#Back substitution
for k in range(n - 1, -1, -1):
b[k] = (b[k] - dot(A[k][k + 1 : n], b[k + 1 : n]))/A[k][k]
return b
I'm working on a problem right now on tridiagonal matrix, i used the tridiagonal matrix algorithim in wiki https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm to implement a solution and i have attempted it but my solution is not complete.
I'm confused and i need help also here is my script using jupyter notebook
import numpy as np
# The diagonals and the solution vector
b = np.array((5, 6, 6, 6, 6, 6, 6, 6, 5), dtype=float) # Main Diagonal
a= np.array((1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Lower Diagonal
c = np.array((1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Upper Diagonal
d = np.array((3, 2, 1, 3, 1, 3, 1, 2, 3), dtype = float) # Solution Vector
#number of rows
n = d.size
newC = np.zeros(n, dtype= float)
newD = np.zeros(n, dtype = float)
x = np.zeros(n, dtype = float)
# the first coefficents
newC[0] = c[0] / b[0]
newD[0] = d[0] / b[0]
for i in range(1, n - 1):
newC[i] = c[i] / (b[i] - a[i] * newC[i - 1])
for i in range(1, n -1):
newD[i] = (d[i] - a[i] * newD[i - 1]) / (b[i] - a[i] * newC[i - 1])
x[n - 1] = newD[n - 1]
for i in reversed(range(0, n - 1)):
x[i] = newD[i] - newC[i] * x[i + 1]
x
The vectors a and c should be the same length as b and d, so just prepend/append zero the them respectively. Additionally, the range should be range(1,n) otherwise your last solution element is 0 when it shouldn't be. You can see this modified code, as well as a comparison to a known algorithm, showing that it gets the same answer.
import numpy as np
# The diagonals and the solution vector
b = np.array((5, 6, 6, 6, 6, 6, 6, 6, 5), dtype=float) # Main Diagonal
a= np.array((0, 1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Lower Diagonal
c = np.array((1, 1, 1, 1, 1, 1, 1, 1, 0), dtype = float) # Upper Diagonal
d = np.array((3, 2, 1, 3, 1, 3, 1, 2, 3), dtype = float) # Solution Vector
print(b.size)
print(a.size)
#number of rows
n = d.size
newC = np.zeros(n, dtype= float)
newD = np.zeros(n, dtype = float)
x = np.zeros(n, dtype = float)
# the first coefficents
newC[0] = c[0] / b[0]
newD[0] = d[0] / b[0]
for i in range(1, n):
newC[i] = c[i] / (b[i] - a[i] * newC[i - 1])
for i in range(1, n):
newD[i] = (d[i] - a[i] * newD[i - 1]) / (b[i] - a[i] * newC[i - 1])
x[n - 1] = newD[n - 1]
for i in reversed(range(0, n - 1)):
x[i] = newD[i] - newC[i] * x[i + 1]
# Test with know algorithme
mat = np.zeros((n, n))
for i in range(n):
mat[i,i] = b[i]
if i < n-1:
mat[i, i+1] = a[i+1]
mat[i+1, i] = c[i]
print(mat)
sol = np.linalg.solve(mat, d)
print(x)
print(sol)
That's because of how a, b, c and d are defined in the wikipedia article. If you look carefully, you'll see that the first element of a is a2, also the loop for newD goes to n. So, to have understandable indices to the arrays, i suggest you add a phantom element a1. And you get:
import numpy as np
# The diagonals and the solution vector
b = np.array((5, 6, 6, 6, 6, 6, 6, 6, 5), dtype=float) # Main Diagonal
a = np.array((np.nan, 1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Lower Diagonal
# with added a1 element
c = np.array((1, 1, 1, 1, 1, 1, 1, 1), dtype = float) # Upper Diagonal
d = np.array((3, 2, 1, 3, 1, 3, 1, 2, 3), dtype = float) # Solution Vector
#number of rows
n = d.size
newC = np.zeros(n, dtype= float)
newD = np.zeros(n, dtype = float)
x = np.zeros(n, dtype = float)
# the first coefficents
newC[0] = c[0] / b[0]
newD[0] = d[0] / b[0]
for i in range(1, n - 1):
newC[i] = c[i] / (b[i] - a[i] * newC[i - 1])
for i in range(1, n): # Add the last iteration `n`
newD[i] = (d[i] - a[i] * newD[i - 1]) / (b[i] - a[i] * newC[i - 1])
x[n - 1] = newD[n - 1]
for i in reversed(range(0, n - 1)):
x[i] = newD[i] - newC[i] * x[i + 1]
x
For a square matrix, each cell is either black (1) or white (0), trying to find the max sub-square whose border is black. Here is my code with Python 2.7, wondering if logically correct? And any performance improvements? Thanks.
My major ideas is, keep track of how many black nodes are on top (continuously) and on left (continuously), which is left and top matrix represents. Then, based on the left and top tracking, for any node, I will try to find minimal value of top and left continuous black node, then I will base the minimal value to see if a square could be formed.
A=[[1,1,0,0,0],
[1,1,1,1,1],
[0,0,1,0,1],
[0,0,1,1,1],
[0,0,0,0,0]]
top=[[0] * len(A[0]) for i in range(len(A))]
left=[[0] * len(A[0]) for i in range(len(A))]
result = 0
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i-1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j-1] + 1 if j > 0 else 1
print top
print left
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i-1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j-1] + 1 if j > 0 else 1
x = min(top[i][j], left[i][j])
if x > 1:
y = min(left[i-x+1][j], top[i][j-x+1])
result = max(result, y)
print result
Edit 1, fix an issue, which is pointed by j_random_hacker.
A = [[1, 1, 0, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 1],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 0]]
A = [[0,1,1],
[1,0,1],
[1,1,1]]
top = [[0] * len(A[0]) for i in range(len(A))]
left = [[0] * len(A[0]) for i in range(len(A))]
result = 0
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i - 1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j - 1] + 1 if j > 0 else 1
print top
print left
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i - 1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j - 1] + 1 if j > 0 else 1
x = min(top[i][j], left[i][j])
if x > 1:
y = min(left[i - x + 1][j], top[i][j - x + 1])
if x == y:
result = max(result, y)
print result
Edit 2, address the issue by j_random_hacker.
A = [[0,1,0,0],
[1,1,1,1],
[0,1,0,1],
[0,1,1,1]]
A = [[0,1,1],
[1,0,1],
[1,1,1]]
A = [[1, 1, 0, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 1],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 0]]
top = [[0] * len(A[0]) for i in range(len(A))]
left = [[0] * len(A[0]) for i in range(len(A))]
result = 0
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i - 1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j - 1] + 1 if j > 0 else 1
print top
print left
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i - 1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j - 1] + 1 if j > 0 else 1
x = min(top[i][j], left[i][j])
while x > 1:
y = min(left[i - x + 1][j], top[i][j - x + 1])
if x == y:
result = max(result, y)
break
x -= 1
print result
Edit 3, new fix
A = [[0,1,0,0],
[1,1,1,1],
[0,1,0,1],
[0,1,1,1]]
A = [[1, 1, 0, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 1],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 0]]
A = [[0,1,1],
[1,0,1],
[1,1,1]]
top = [[0] * len(A[0]) for i in range(len(A))]
left = [[0] * len(A[0]) for i in range(len(A))]
result = 0
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i - 1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j - 1] + 1 if j > 0 else 1
print top
print left
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == 1:
top[i][j] = top[i - 1][j] + 1 if i > 0 else 1
left[i][j] = left[i][j - 1] + 1 if j > 0 else 1
x = min(top[i][j], left[i][j])
while x > 1:
y = min(left[i - x + 1][j], top[i][j - x + 1])
if x <= y:
result = max(result, x)
break
x -= 1
print result
This isn't logically correct, as the following simple counterexample shows:
011
101
111
This array contains no bordered square, but your code reports that it contains a square of edge length 3. You need either a third nested loop through all candidate square sizes down from x to 1 (making the solution O(n^3)-time) or, possibly, some more sophisticated data structure that enables an equivalent check to be performed faster.
[EDIT to address updated algorithm]
The new algorithm thinks there is no bordered square in either
0100
1111 1111
0101 or 0101
0111 0111
despite there being a 3x3 one in each.
Stop guessing at fixes and think about how to break down the set of all possible locations of bordered squares into sets that you can efficiently (or even not-so-efficiently) check. As I tried to say at the top: For each possible bottom-right corner of a bordered square, your code is currently only checking one rectangle. But many more rectangles could have (i, j) as a bottom-right corner -- where are the tests for them?