-
Notifications
You must be signed in to change notification settings - Fork 2
/
tsp.go
111 lines (91 loc) · 1.94 KB
/
tsp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main
import (
"bufio"
"fmt"
"log"
"math"
"os"
"strconv"
"strings"
)
const (
inf = 4294967295.8574839
)
// Node is a city
type Node struct {
X float64
Y float64
visited bool
}
func (n Node) distanceTo(node Node) float64 {
return math.Sqrt(math.Pow((n.X-node.X), 2) + math.Pow((n.Y-node.Y), 2))
}
func tsp(elements []Node) int {
totalDistance := 0.0
elements[0].visited = true
lastVisited := elements[0]
for i := 1; i < len(elements); i++ {
minDist := inf
citiesOfInterest := make([]*Node, 0)
for j := 0; j < len(elements); j++ {
if prospect := &elements[j]; !prospect.visited {
if distance := lastVisited.distanceTo(*prospect); distance < minDist {
minDist = distance
citiesOfInterest = append(citiesOfInterest, prospect)
}
}
}
for _, prospect := range citiesOfInterest { // this is to handle the weird tie rule in the assignment
if lastVisited.distanceTo(*prospect) == minDist {
prospect.visited = true
lastVisited = *prospect
totalDistance += minDist
break
}
}
}
// go home
totalDistance += lastVisited.distanceTo(elements[0])
return int(math.Round(totalDistance))
}
func main() {
fmt.Println(tsp(loadData("course4/week3/tsp/data.txt")))
}
func loadData(filepath string) []Node {
nodes := make([]Node, 0)
f, err := os.Open(filepath)
check(err)
defer f.Close()
scanner := bufio.NewScanner(f)
row := -1
for scanner.Scan() {
if row == -1 {
row++
continue
}
parseRowIntoEntry(&nodes, &row, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
return nodes
}
func parseRowIntoEntry(items *[]Node, index *int, row string) {
rowSlice := strings.Fields(row)
X, err := strconv.ParseFloat(rowSlice[1], 64)
check(err)
Y, err := strconv.ParseFloat(rowSlice[2], 64)
check(err)
visited := false
*items = append(*items, Node{
X,
Y,
visited,
})
*index++
}
func check(err error) {
if err != nil {
log.Panicln(err)
}
}