79 lines
1.5 KiB
Go
79 lines
1.5 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"cmp"
|
||
|
|
||
|
pq "github.com/emirpasic/gods/v2/queues/priorityqueue"
|
||
|
)
|
||
|
|
||
|
type Position struct {
|
||
|
y, x int
|
||
|
}
|
||
|
|
||
|
func (p *Position) add(v Position) Position {
|
||
|
return Position{
|
||
|
y: p.y + v.y,
|
||
|
x: p.x + v.x,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type QueueEntry struct {
|
||
|
time int
|
||
|
pos Position
|
||
|
}
|
||
|
|
||
|
func byTime(a, b QueueEntry) int {
|
||
|
return cmp.Compare(a.time, b.time)
|
||
|
}
|
||
|
|
||
|
func minimumTime(grid [][]int) int {
|
||
|
if grid[0][1] > 1 && grid[1][0] > 1 {
|
||
|
return -1
|
||
|
}
|
||
|
DIRECTIONS := []Position{
|
||
|
Position{1, 0}, Position{-1, 0}, Position{0, 1}, Position{0, -1},
|
||
|
}
|
||
|
|
||
|
rows, cols := len(grid), len(grid[0])
|
||
|
visited := make([][]bool, rows)
|
||
|
for i, _ := range visited {
|
||
|
visited[i] = make([]bool, cols)
|
||
|
}
|
||
|
|
||
|
valid := func(pos Position) bool {
|
||
|
return pos.y >= 0 && pos.y < len(visited) &&
|
||
|
pos.x >= 0 && pos.x < len(visited[pos.y]) &&
|
||
|
!visited[pos.y][pos.x]
|
||
|
}
|
||
|
|
||
|
q := pq.NewWith[QueueEntry](byTime)
|
||
|
q.Enqueue(QueueEntry{grid[0][0], Position{0, 0}})
|
||
|
|
||
|
for current, ok := q.Dequeue(); ok; current, ok = q.Dequeue() {
|
||
|
if current.pos.y == rows-1 && current.pos.x == cols-1 {
|
||
|
return current.time
|
||
|
}
|
||
|
|
||
|
if visited[current.pos.y][current.pos.x] {
|
||
|
continue
|
||
|
}
|
||
|
visited[current.pos.y][current.pos.x] = true
|
||
|
|
||
|
for _, dir := range DIRECTIONS {
|
||
|
next := current.pos.add(dir)
|
||
|
if !valid(next) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
waiting := 0
|
||
|
if (grid[next.y][next.x]-current.time)%2 == 0 {
|
||
|
waiting = 1
|
||
|
}
|
||
|
|
||
|
q.Enqueue(QueueEntry{pos: next, time: max(grid[next.y][next.x]+waiting, current.time+1)})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return -1
|
||
|
}
|