Wednesday, December 3, 2008

Project Euler p83 and Dijkstra's algorithm

Problem definition:
In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by moving left, right, up, and down, is indicated in bold and is equal to 2297.

131 673 234 103 18
201 96  342 965 150
630 803 746 422 111
537 699 497 121 956
805 732 524 37  331

Find the minimal path sum, in matrix.txt , a 31K text file containing a 80 by 80 matrix, from the top left to the bottom right by moving left, right, up, and down.

Problem is solved with the help of Dijkstra's algorithm
Answer is calculated in a 2.5 seconds. Also it is not optimized,- computes distances to all nodes in network. To speed up - when we find target node - we can only check these nodes which distance is less than target node distance. Also this code suits equally well for solving project euler problem no 81 - only change shortestpath() function parameter "directions". And finally - this solution shows shortest path visually,- prints it to screen. Program code:

import time as t

def readmatrix(filename):
f=open(filename, 'r')
m=[map(lambda x: int(x),r.strip().split(",")) for r in f.readlines()]
return m

def nextcell(dctresults):
minw = 10000000
mink = None
for k in dctresults:
if not dctresults[k][2]:
if dctresults[k][1] < minw:
minw = dctresults[k][1]
mink = k
return mink

def analyzecell(lstmat, tupcell, lstdirec, dctresults):
i,j = tupcell
for dr in lstdirec:
di,dj = dr
if (i+di) in range(len(lstmat)) and (j+dj) in range(len(lstmat)):
if not dctresults.has_key((i+di,j+dj)):
dctresults[(i+di,j+dj)] = [(i,j),dctresults[(i,j)][1]+lstmat[i+di][j+dj],False]
oldw = dctresults[(i+di,j+dj)][1]
neww = dctresults[(i,j)][1]+lstmat[i+di][j+dj]
if neww < oldw:
dctresults[(i+di,j+dj)][0] = (i,j)
dctresults[(i+di,j+dj)][1] = neww
dctresults[(i,j)][2] = True

def shortestpath(filename, directions):
mat = readmatrix(filename)
results = {}
results[(0,0)] = [None,mat[0][0],False]
cell = nextcell(results)
while cell:
cell = nextcell(results)
return results, results[(len(mat)-1,len(mat)-1)][1], mat

def showpath(res, inpmat):
print ' '+'-'*len(inpmat)+' '
pathcells = []
curc = (len(inpmat)-1,len(inpmat)-1)
while curc:
pathcells += [curc]
curc = res[curc][0]
for i in range(len(inpmat)):
for j in range(len(inpmat)):
s+= '#' if (i,j) in pathcells else '.'
print s+'|'
print ' '+'-'*len(inpmat)+' '

t1 = t.time()*1000
resd, pathsum, mat = shortestpath('matrix.txt',[(-1,0),(+1,0),(0,-1),(0,+1)])
t2 = t.time()*1000
print 'Shortest path sum', pathsum, '; Calculation time is ', int(t2-t1), 'ms'
showpath(resd, mat)

Have fun with shortest path algorithms !!!

No comments:

Post a Comment

Comment will be posted after comment moderation.
Thank you for your appreciation.