amhrpi
amhrpi

Reputation: 53

Optimizing python code, reducing allocation/ deallocation times

I am trying to solve a programming challenge question from a certain website which I would not like to mention here.

The problem is as follows:

There is an square board with N*N points. An insect starts out at a particular point (x1,y1). It can jump to any point (x2,y2) if |x1-x2|+|y1-y2| <= S. Also, some points contain water on which the insect cannot jump. How many different paths can it take in M jumps? Note that it can remain at the same point by jumping in place.

The integers N, S, M are given and so is the initial board configuration.

I am pretty sure that my solution is correct and can be proved by induction. I convert the board into a graph (adjacency list) with edges between points that make a valid insect jump. Then its just a matter of iterating M times and updating path counts.

My main concern is that the code needs to be optimized such that it works over multiple test cases without allocating/ deallocating too many times which slows down the running time. Also it would be great if anyone could suggest optimizations within the algorithm itself.

Thanks!

import sys

#The board on which Jumping insect moves.
#The max size in any test case is 200 * 200
board = [['_']*200 for j in xrange(200)]

#Graph in the form of an adjancency list created from the board
G = [list() for i in xrange(200*200)]


def paths(N,M,S):
    '''Calculates the total number of paths insect takes
    The board size is N*N, Length of paths: M,
    Insect can jusp from square u to square v if ||u-v|| <=S
    Here ||u-v|| refers to the 1 norm'''

    # Totals paths are modulo 1000000007
    MOD = 1000000007

    # Clearing adjacency list for this testcase
    for i in xrange(N*N): del(G[i][:])

    s = -1 #Starting point s

    #Creating G adjacency list 
    # Point 'L' represents starting point
    # Point 'P' cannot be accessed by the insect
    for u in xrange(N*N):
        x1, y1 = u/N, u%N
        if board[x1][y1] == 'L': s = u
        elif board[x1][y1] == 'P': continue
        for j in xrange(S+1):
            for k in xrange(S+1-j):
                x2, y2 = x1+j, y1+k
                if x2 < N and y2 < N and not board[x2][y2] == 'P':
                    v = x2*N+y2
                    G[u].append(v)
                    if not u == v: G[v].append(u)
                if j > 0 and k > 0:
                    x2, y2 = x1+j, y1-k
                    if x2 < N and y2 >= 0 and not board[x2][y2] == 'P':
                        v = x2*N+y2
                        G[u].append(v)
                        G[v].append(u)                

    # P stores path counts
    P = [[0 for i in xrange(N*N)] for j in xrange(2)]
    # Setting count for starting position to 1
    P[0][s] = 1

    # Using shifter to toggle between prev and curr paths
    shifter, prev, curr = 0, 0, 0

    # Calculating paths
    for i in xrange(M):
        prev, curr = shifter %2, (shifter+1)%2

        #Clearing Path counts on curr
        for i in xrange(N*N): P[curr][i] = 0 
        for u in xrange(N*N):
            if P[prev][u] == 0: continue
            for v in G[u]:
                P[curr][v] = (P[curr][v]+P[prev][u]) % MOD
        shifter = (shifter+1)%2
    return (sum(P[curr])%MOD)

#Number of testcases
num = int(sys.stdin.readline().split()[0])

results = []

# Reading in test cases
for i in xrange(num):
    N, M, S = [int(j) for j in sys.stdin.readline().split()]
    for j in xrange(N):
        board[j][:N] = list(sys.stdin.readline().split()[0])
    results.append(paths(N,M,S))

for result in results:
    print result

Upvotes: 4

Views: 185

Answers (1)

Michael Dillon
Michael Dillon

Reputation: 32392

This is the kind of thing that numpy is good for although you might be able to manage it for this specific use case by using the array and struct modules.

Upvotes: 1

Related Questions