Project Euler problem 81 asks:
In the 5 by 5 matrix below,
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
the minimal path sum from the top left to the bottom right, by only moving to the right and down, is
131 → 201 → 96 → 342 → 746 → 422 → 121 → 37 → 331
and is equal to 2427.
Find the minimal path sum, in
matrix.txt
(right click and 'Save Link/Target As...'), a 31K text file containing a 80 by 80 matrix, from the top left to the bottom right by only moving right and down.
Below is a Go solution using uniform-cost search to build a search tree. It works on the toy small problem but on the 80x80 matrix it runs out of space. Could anyone that is up for a challenge help improve this still using this solution? By the way, this is the first program of any consequence I have written in Go and I am try to learn the language.
package main
import (
"bufio"
"container/heap"
"fmt"
"io"
"os"
"strconv"
"strings"
)
var matrix [][]int = make([][]int, 0, 80)
func main() {
f, _ := os.Open("matrix.txt")
r := bufio.NewReader(f)
defer f.Close()
for {
s, ok := r.ReadString('\n')
if ok == io.EOF {
break
}
s = strings.Trim(s, "\n")
stringArr := strings.Split(s, ",")
tmp := make([]int, 0)
for i := 0; i < 80; i++ {
v, _ := strconv.Atoi(stringArr[i])
tmp = append(tmp, v)
}
matrix = append(matrix, tmp)
}
//fmt.Println(matrix)
fmt.Println(uniformCostSearch(treeNode{0, 0, 4445, 0}))
}
func (node treeNode) getPriority(y, x int) int {
return matrix[y][x]
}
type Node interface {
// Neighbors returns a slice of vertices that are adjacent to v.
Neighbors(v Node) []Node
}
// An treeNode is something we manage in a priority queue.
type treeNode struct {
X int
Y int
priority int // The priority of the item in the queue.
Index int // The index of the item in the heap.
}
func (node treeNode) Neighbors() []*treeNode {
tmp := []*treeNode{ //&treeNode{X: node.X - 1, Y: node.Y},
&treeNode{X: node.X + 1, Y: node.Y},
//&treeNode{X: node.X, Y: node.Y - 1},
&treeNode{X: node.X, Y: node.Y + 1}}
childNodes := make([]*treeNode, 0)
for _, n := range tmp {
if n.X >= 0 && n.Y >= 0 && n.X <= 80 && n.Y <= 80 {
n.priority = node.priority + n.getPriority(n.Y, n.X)
childNodes = append(childNodes, n)
}
}
return childNodes
}
func uniformCostSearch(startNode treeNode) int {
frontier := make(PriorityQueue, 0, 10000)
closedSet := make([]*treeNode, 0)
heap.Push(&frontier, &startNode)
for frontier.Len() > 0 {
fmt.Println(frontier.Len())
currentNode := heap.Pop(&frontier).(*treeNode)
if currentNode.X == 79 && currentNode.Y == 79 {
return currentNode.priority
} else {
closedSet = append(closedSet, currentNode)
}
possibleMoves := currentNode.Neighbors()
for _, move := range possibleMoves {
explored := false
for _, seen := range closedSet {
if seen.X == move.X && seen.Y == move.Y {
explored = true
break
}
}
if explored {
continue
}
// check that frontier does not contain this node and
// if it does then compare the cost so far
for index, node := range frontier {
if node.X == move.X && node.Y == move.Y && move.priority < node.priority {
fmt.Println("removing")
heap.Remove(&frontier, index)
break
}
}
heap.Push(&frontier, move)
}
}
return -1
}
// A PriorityQueue implements heap.Interface and holds treeNodes.
type PriorityQueue []*treeNode
func (pq PriorityQueue) Len() int {
return len(pq)
}
func (pq PriorityQueue) Less(i, j int) bool {
// We want Pop to give us the lowest priority so we use greater than here.
return pq[i].priority < pq[j].priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].Index = i
pq[j].Index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
// To simplify indexing expressions in these methods, we save a copy of the
// slice object. We could instead write (*pq)[i].
a := *pq
n := len(a)
a = a[0 : n+1]
item := x.(*treeNode)
item.Index = n
a[n] = item
*pq = a
}
func (pq *PriorityQueue) Pop() interface{} {
a := *pq
n := len(a)
item := a[n-1]
item.Index = -1 // for safety
*pq = a[0 : n-1]
return item
}