Skip to content

Commit

Permalink
Merge b5269d6 into 06c53ac
Browse files Browse the repository at this point in the history
  • Loading branch information
vaskoz committed Jun 14, 2019
2 parents 06c53ac + b5269d6 commit 8b8f6e3
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,5 @@ problems from
* [Day 288](https://github.com/vaskoz/dailycodingproblem-go/issues/590)
* [Day 290](https://github.com/vaskoz/dailycodingproblem-go/issues/594)
* [Day 291](https://github.com/vaskoz/dailycodingproblem-go/issues/596)
* [Day 294](https://github.com/vaskoz/dailycodingproblem-go/issues/600)
* [Day 295](https://github.com/vaskoz/dailycodingproblem-go/issues/601)
81 changes: 81 additions & 0 deletions day294/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package day294

import (
"errors"
)

// Elevation is a map of locations to their elevations.
type Elevation map[int]int

// PathDistance represents the distance for a particular path.
type PathDistance map[int]map[int]int

// MaxInt is the largest int.
const MaxInt = int(^uint(0) >> 1)

var errNotPossible = errors.New("no path possible")

// ErrNotPossible is the error returned if a path doesn't exist.
func ErrNotPossible() error {
return errNotPossible
}

// ShortestRunnerPath with the condition that the route goes entirely
// uphill at first, and then entirely downhill.
// Always starts at location 0 and end at location 0.
func ShortestRunnerPath(elevations Elevation, paths PathDistance) (int, error) {
min := MaxInt
startElev := elevations[0]
for next, distance := range paths[0] {
nextElev := elevations[next]
if nextElev > startElev {
dist, err := shortestRunnerPath(elevations, paths, map[int]struct{}{}, true, next)
if err == nil && dist+distance < min {
min = dist + distance
}
}
}
if min == MaxInt {
return 0, ErrNotPossible()
}
return min, nil
}

func shortestRunnerPath(
elevations Elevation,
paths PathDistance,
visited map[int]struct{},
up bool,
n int) (int, error) {
if n == 0 {
return 0, nil
}
min := MaxInt
currentElevation := elevations[n]
for next, distance := range paths[n] {
if _, visit := visited[next]; !visit {
nextElevation := elevations[next]
if up && nextElevation > currentElevation {
visited[next] = struct{}{}
dist, err := shortestRunnerPath(elevations, paths, visited, true, next)
totalDist := dist + distance
if err == nil && totalDist < min {
min = totalDist
}
delete(visited, next)
} else if nextElevation < currentElevation {
visited[next] = struct{}{}
dist, err := shortestRunnerPath(elevations, paths, visited, false, next)
totalDist := dist + distance
if err == nil && totalDist < min {
min = totalDist
}
delete(visited, next)
}
}
}
if min == MaxInt {
return 0, ErrNotPossible()
}
return min, nil
}
144 changes: 144 additions & 0 deletions day294/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package day294

import "testing"

// nolint
var testcases = []struct {
elevations Elevation
paths PathDistance
shortestRoute int
err error
}{
{
Elevation{
0: 15,
1: 10,
2: 25,
},
PathDistance{
0: {
2: 5,
},
1: {
0: 1,
},
2: {
1: 7,
},
},
0,
ErrNotPossible(),
},
{
Elevation{
0: 10,
1: 25,
2: 15,
},
PathDistance{
0: {
1: 15,
2: 5,
},
1: {
0: 1,
},
2: {
1: 7,
0: 30,
},
},
13,
nil,
},
{
Elevation{
0: 10,
1: 5,
2: 7,
},
PathDistance{
0: {
1: 5,
2: 10,
},
1: {
0: 5,
},
2: {
0: 10,
},
},
0,
ErrNotPossible(),
},
{
Elevation{
0: 10,
1: 5,
2: 15,
},
PathDistance{
0: {
1: 5,
2: 10,
},
1: {
0: 5,
},
2: {
0: 10,
},
},
20,
nil,
},
{
Elevation{
0: 5,
1: 25,
2: 15,
3: 20,
4: 10,
},
PathDistance{
0: {
1: 10,
2: 8,
3: 15,
},
1: {
3: 12,
},
2: {
4: 10,
},
3: {
4: 5,
0: 17,
},
4: {
0: 10,
},
},
28,
nil,
},
}

func TestShortestRunnerPath(t *testing.T) {
t.Parallel()
for _, tc := range testcases {
if result, err := ShortestRunnerPath(tc.elevations, tc.paths); result != tc.shortestRoute || err != tc.err {
t.Errorf("Expected (%v,%v), got (%v,%v)", tc.shortestRoute, tc.err, result, err)
}
}
}

func BenchmarkShortestRunnerPath(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
ShortestRunnerPath(tc.elevations, tc.paths) // nolint
}
}
}

0 comments on commit 8b8f6e3

Please sign in to comment.