package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pair struct {
	d int64
	v int
}
type hp []pair

func (h hp) Len() int              { return len(h) }
func (h hp) Less(i, j int) bool    { return h[i].d < h[j].d }
func (h hp) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{})   { *h = append(*h, v.(pair)) }
func (h *hp) Pop() (v interface{}) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }

// github.com/EndlessCheng/codeforces-go
func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type nb struct {
		to int
		wt int64
	}

	var n, m, v, w int
	var wt int64
	Fscan(in, &n, &m)
	g := make([][]nb, n+1)
	for ; m > 0; m-- {
		Fscan(in, &v, &w, &wt)
		g[v] = append(g[v], nb{w, wt})
		g[w] = append(g[w], nb{v, wt})
	}

	const inf int64 = 1e18
	dist := make([]int64, n+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[1] = 0
	fa := make([]int, n+1)
	h := hp{{0, 1}}
	for len(h) > 0 {
		p := Pop(&h).(pair)
		d, v := p.d, p.v
		if dist[v] < d {
			continue
		}
		for _, e := range g[v] {
			w := e.to
			if newD := d + e.wt; newD < dist[w] {
				dist[w] = newD
				fa[w] = v
				Push(&h, pair{newD, w})
			}
		}
	}
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	path := []int{}
	for x := n; x > 0; x = fa[x] {
		path = append(path, x)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() { run(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pair struct {
	d int64
	v int
}
type hp []pair

func (h hp) Len() int              { return len(h) }
func (h hp) Less(i, j int) bool    { return h[i].d < h[j].d }
func (h hp) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{})   { *h = append(*h, v.(pair)) }
func (h *hp) Pop() (v interface{}) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }

// github.com/EndlessCheng/codeforces-go
func CF20C(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type edge struct {
		to int
		w  int64
	}

	var n, m, v, w int
	var weight int64
	Fscan(in, &n, &m)
	g := make([][]edge, n+1)
	for ; m > 0; m-- {
		Fscan(in, &v, &w, &weight)
		g[v] = append(g[v], edge{w, weight})
		g[w] = append(g[w], edge{v, weight})
	}

	const inf int64 = 1e18
	dist := make([]int64, n+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[1] = 0
	fa := make([]int, n+1)
	h := hp{{0, 1}}
	for len(h) > 0 {
		p := Pop(&h).(pair)
		v := p.v
		for _, e := range g[v] {
			w := e.to
			if newD := dist[v] + e.w; newD < dist[w] {
				dist[w] = newD
				fa[w] = v
				Push(&h, pair{newD, w})
			}
		}
	}
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	path := []int{}
	for x := n; x > 0; x = fa[x] {
		path = append(path, x)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() { CF20C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pair struct {
	d int64
	v int
}
type hp []pair

func (h hp) Len() int              { return len(h) }
func (h hp) Less(i, j int) bool    { return h[i].d < h[j].d }
func (h hp) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{})   { *h = append(*h, v.(pair)) }
func (h *hp) Pop() (v interface{}) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }

// github.com/EndlessCheng/codeforces-go
func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type nb struct {
		to int
		wt int64
	}

	var n, m, v, w int
	var wt int64
	Fscan(in, &n, &m)
	g := make([][]nb, n+1)
	for ; m > 0; m-- {
		Fscan(in, &v, &w, &wt)
		g[v] = append(g[v], nb{w, wt})
		g[w] = append(g[w], nb{v, wt})
	}

	const inf int64 = 1e18
	dist := make([]int64, n+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[1] = 0
	fa := make([]int, n+1)
	h := hp{{0, 1}}
	for len(h) > 0 {
		p := Pop(&h).(pair)
		d, v := p.d, p.v
		if dist[v] < d {
			continue
		}
		for _, e := range g[v] {
			w := e.to
			if newD := d + e.wt; newD < dist[w] {
				dist[w] = newD
				fa[w] = v
				Push(&h, pair{newD, w})
			}
		}
	}
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	vs := []int{}
	for x := n; x > 0; x = fa[x] {
		vs = append(vs, x)
	}
	for i := len(vs) - 1; i >= 0; i-- {
		Fprint(out, vs[i], " ")
	}
}

func main() { run(os.Stdin, os.Stdout) }

package main

// checker used
// https://codeforces.com/contest/20/problem/C
// https://www.spoj.com/problems/EZDIJKST/
import (
	"bufio"
	"fmt"
	"os"
)

type Graph struct {
	edges          Edges
	startingIdxFor map[int]int
	endingIdxFor   map[int]int
	dist           map[int]float64
}

func (g *Graph) add(u, v int, w float64) {
	g.edges = append(g.edges, &Edge{u, v, w})
	//g.edges = append(g.edges, &Edge{v, u, w}) roads are directed
}

type GraphWithMaps struct {
	graph map[int][]*Edge
	dist  map[int]float64
	path  map[int]int
}

type priorityQueue []distanceNode

// Init establishes the heap invariants required by the other routines in this package.
// Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// The complexity is O(n) where n = h.Len().
func Init(pq *priorityQueue) {
	// heapify
	n := len(priorityQueue{})
	for i := n/2 - 1; i >= 0; i-- {
		down(pq, i, n)
	}
}

// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(pq *priorityQueue, dn distanceNode) {
	*pq = append(*pq, dn)
	up(pq, len(*pq)-1)
}

// Pop removes and returns the minimum element (according to Less) from the heap.
// The complexity is O(log n) where n = h.Len().
// Pop is equivalent to Remove(h, 0).
func Pop(pq *priorityQueue) distanceNode {
	n := len(*pq) - 1
	(*pq)[0], (*pq)[n] = (*pq)[n], (*pq)[0]
	down(pq, 0, n)

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Remove removes and returns the element at index i from the heap.
// The complexity is O(log n) where n = h.Len().
func Remove(pq *priorityQueue, i int) distanceNode {
	n := len(*pq) - 1
	if n != i {
		(*pq)[i], (*pq)[n] = (*pq)[n], (*pq)[i]
		if !down(pq, i, n) {
			up(pq, i)
		}
	}

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log n) where n = h.Len().
func Fix(pq *priorityQueue, i int) {
	if !down(pq, i, len(*pq)) {
		up(pq, i)
	}
}

func up(pq *priorityQueue, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		j = i
	}
}

func down(pq *priorityQueue, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && (*pq)[j2].dist < (*pq)[j1].dist {
			j = j2 // = 2*i + 2  // right child
		}
		if !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		i = j
	}
	return i > i0
}

type Edges []*Edge

func (a Edges) Len() int           { return len(a) }
func (a Edges) Less(i, j int) bool { return a[i].u < a[j].u }
func (a Edges) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func NewGraph() *Graph {
	return &Graph{
		edges:          make([]*Edge, 0),
		startingIdxFor: make(map[int]int),
		endingIdxFor:   make(map[int]int),
		dist:           make(map[int]float64),
	}
}

func NewGraphWithMaps() *GraphWithMaps {
	return &GraphWithMaps{
		graph: make(map[int][]*Edge),
		dist:  make(map[int]float64),
		path:  make(map[int]int),
	}
}

func (g *GraphWithMaps) distInf(u, v int) {
	g.dist[u] = infinity
	g.dist[v] = infinity
}

func (g *GraphWithMaps) connect(u, v int, weight float64, isDirectedEdge bool) {
	vEdges, ok := g.graph[u]
	if !ok {
		vEdges = []*Edge{}
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	} else {
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	}
	if !isDirectedEdge {
		uEdges, ok := g.graph[v]
		if !ok {
			uEdges = []*Edge{}
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		} else {
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		}
	}
}

type Edge struct {
	u, v int
	dist float64
}

type distanceNode struct {
	to   int
	dist float64
}

var infinity = 100000000000.0

func (g *Graph) DijkstraTarget(source, target int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraTarget(source, target int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
				g.path[outgoing.v] = vertex.to
			}
		}
	}
}

func (g *GraphWithMaps) printPath(source, target int) []int {
	computedPath := []int{}
	_, ok := g.path[target]
	if !ok {
		computedPath = append(computedPath, -1)
		return computedPath
	}
	computedPath = append(computedPath, target)
	startFrom := target
	for {
		nextTo, ok := g.path[startFrom]
		if !ok {
			break
		}
		if nextTo == source {
			computedPath = append(computedPath, source)
			return computedPath
		}
		computedPath = append(computedPath, nextTo)
		startFrom = nextTo
	}
	computedPath = append(computedPath, -1)
	return computedPath
}

func main() {
	g3 := NewGraphWithMaps()
	in := bufio.NewReader(os.Stdin)
	var n, m int
	fmt.Fscanf(in, "%d %d\n", &n, &m)
	for i := 0; i < m; i++ {
		var u, v, w int
		fmt.Fscanf(in, "%d %d %d\n", &u, &v, &w)
		g3.connect(u, v, float64(w), false)
		g3.distInf(u, v)
	}
	g3.DijkstraTarget(1, n)
	path := g3.printPath(1, n)
	for i := len(path) - 1; i >= 0; i-- {
		fmt.Printf("%d ", path[i])
	}

}

package main

import (
	"bufio"
	"fmt"
	"os"
)

type Graph struct {
	edges          Edges
	startingIdxFor map[int]int
	endingIdxFor   map[int]int
	dist           map[int]float64
}

func (g *Graph) add(u, v int, w float64) {
	g.edges = append(g.edges, &Edge{u, v, w})
	//g.edges = append(g.edges, &Edge{v, u, w}) roads are directed
}

type GraphWithMaps struct {
	graph map[int][]*Edge
	dist  map[int]float64
	path  map[int]int
}

type priorityQueue []distanceNode

// Init establishes the heap invariants required by the other routines in this package.
// Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// The complexity is O(n) where n = h.Len().
func Init(pq *priorityQueue) {
	// heapify
	n := len(priorityQueue{})
	for i := n/2 - 1; i >= 0; i-- {
		down(pq, i, n)
	}
}

// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(pq *priorityQueue, dn distanceNode) {
	*pq = append(*pq, dn)
	up(pq, len(*pq)-1)
}

// Pop removes and returns the minimum element (according to Less) from the heap.
// The complexity is O(log n) where n = h.Len().
// Pop is equivalent to Remove(h, 0).
func Pop(pq *priorityQueue) distanceNode {
	n := len(*pq) - 1
	(*pq)[0], (*pq)[n] = (*pq)[n], (*pq)[0]
	down(pq, 0, n)

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Remove removes and returns the element at index i from the heap.
// The complexity is O(log n) where n = h.Len().
func Remove(pq *priorityQueue, i int) distanceNode {
	n := len(*pq) - 1
	if n != i {
		(*pq)[i], (*pq)[n] = (*pq)[n], (*pq)[i]
		if !down(pq, i, n) {
			up(pq, i)
		}
	}

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log n) where n = h.Len().
func Fix(pq *priorityQueue, i int) {
	if !down(pq, i, len(*pq)) {
		up(pq, i)
	}
}

func up(pq *priorityQueue, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		j = i
	}
}

func down(pq *priorityQueue, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && (*pq)[j2].dist < (*pq)[j1].dist {
			j = j2 // = 2*i + 2  // right child
		}
		if !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		i = j
	}
	return i > i0
}

type Edges []*Edge

func (a Edges) Len() int           { return len(a) }
func (a Edges) Less(i, j int) bool { return a[i].u < a[j].u }
func (a Edges) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func NewGraph() *Graph {
	return &Graph{
		edges:          make([]*Edge, 0),
		startingIdxFor: make(map[int]int),
		endingIdxFor:   make(map[int]int),
		dist:           make(map[int]float64),
	}
}

func NewGraphWithMaps() *GraphWithMaps {
	return &GraphWithMaps{
		graph: make(map[int][]*Edge),
		dist:  make(map[int]float64),
		path:  make(map[int]int),
	}
}

func (g *GraphWithMaps) distInf(u, v int) {
	g.dist[u] = infinity
	g.dist[v] = infinity
}

func (g *GraphWithMaps) connect(u, v int, weight float64, isDirectedEdge bool) {
	vEdges, ok := g.graph[u]
	if !ok {
		vEdges = []*Edge{}
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	} else {
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	}
	if !isDirectedEdge {
		uEdges, ok := g.graph[v]
		if !ok {
			uEdges = []*Edge{}
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		} else {
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		}
	}
}

type Edge struct {
	u, v int
	dist float64
}

type distanceNode struct {
	to   int
	dist float64
}

var infinity = 100000000000.0

func (g *Graph) DijkstraTarget(source, target int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraTarget(source, target int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	visited := make(map[int]bool)
	for len(pq) > 0 {
		vertex := Pop(&pq)
		_, ok := visited[vertex.to]
		if ok {
			continue
		}
		visited[vertex.to] = true
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			_, ok := visited[outgoing.v]
			if !ok && g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
				g.path[outgoing.v] = vertex.to
			}
		}
	}
}

func (g *GraphWithMaps) printPath(source, target int) []int {
	computedPath := []int{}
	_, ok := g.path[target]
	if !ok {
		computedPath = append(computedPath, -1)
		return computedPath
	}
	computedPath = append(computedPath, target)
	startFrom := target
	for {
		nextTo, ok := g.path[startFrom]
		if !ok {
			break
		}
		if nextTo == source {
			computedPath = append(computedPath, source)
			return computedPath
		}
		computedPath = append(computedPath, nextTo)
		startFrom = nextTo
	}
	computedPath = append(computedPath, -1)
	return computedPath
}

func main() {
	g3 := NewGraphWithMaps()
	in := bufio.NewReader(os.Stdin)
	var n, m int
	fmt.Fscanf(in, "%d %d\n", &n, &m)
	for i := 0; i < m; i++ {
		var u, v, w int
		fmt.Fscanf(in, "%d %d %d\n", &u, &v, &w)
		g3.connect(u, v, float64(w), false)
		g3.distInf(u, v)
	}
	g3.DijkstraTarget(1, n)
	path := g3.printPath(1, n)
	for i := len(path) - 1; i >= 0; i-- {
		fmt.Printf("%d ", path[i])
	}
}

package main

import (
	"bufio"
	"fmt"
	"math"
	"math/rand"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]float64, MAX)
	visited = make([]bool, MAX)
	pred = make([]int, MAX)
	rnd := rand.Perm(m)
	temp := make([][3]int, m)
	for i := 0; i < m; i++ {
		temp[rnd[i]] = [3]int{readInt(), readInt(), readInt()}
	}
	for i := 0; i < m; i++ {
		u, v, w := temp[i][0], temp[i][1], temp[i][2]
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []float64
var visited []bool
var pred []int

var inf float64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src, dst int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	pq := New()
	pq.Add(0, src)
	for pq.Len() > 0 {
		_, v := pq.Min()
		vertex := v.(int)
		visited[vertex] = false
		for _, aj := range adj[vertex] {
			if float64(aj.weight)+dist[vertex] < dist[aj.to] {
				dist[aj.to] = float64(aj.weight) + dist[vertex]
				pred[aj.to] = vertex
				if dst != aj.to && !visited[aj.to] {
					pq.Add(dist[aj.to], aj.to)
					visited[aj.to] = true
				}
			}
		}
	}
}

type Edge struct {
	to     int
	weight int
}

// Fibonacci Heap implementation from https://github.com/alonsovidales/go_fibanaccy_heap/
type node struct {
	mark    bool
	rank    uint64
	value   float64
	content interface{}
	parent  *node
	child   *node
	l       *node
	r       *node
}

// FibonacciHeap Fibbonacy heap: http://en.wikipedia.org/wiki/Fibonacci_heap
type FibonacciHeap struct {
	min    *node
	nodes  map[interface{}]*node
	length int
}

// New Returns a new FibonacciHeap instance
func New() *FibonacciHeap {
	return &FibonacciHeap{
		nodes: make(map[interface{}]*node),
	}
}

// GetScore Returns the score of an element in the heap if exists, if not the
// second returned value will be a false
func (fh *FibonacciHeap) GetScore(c interface{}) (v float64, f bool) {
	node, f := fh.nodes[c]
	if f {
		v = node.value
	}

	return
}

// Add adds a new value to the Fibonacci heap, v will be used as score for the
// new element, and c has to contain the element to be added
func (fh *FibonacciHeap) Add(v float64, c interface{}) {
	newNode := &node{
		mark:    false,
		rank:    1,
		value:   v,
		content: c,
	}

	fh.nodes[c] = newNode

	// Add the node to the roots
	if fh.min == nil {
		fh.min = newNode
		newNode.l = newNode
		newNode.r = newNode
		fh.min = newNode
	} else {
		fh.min.l.r = newNode
		newNode.l = fh.min.l
		newNode.r = fh.min
		fh.min.l = newNode

		if fh.min.value > v {
			fh.min = newNode
		}
	}
	fh.length++
}

// DecreaseScore decreases the score for an existing element in the heap, if
// the element is not found in the heap this method will add it
func (fh *FibonacciHeap) DecreaseScore(v float64, c interface{}) {
	node, exists := fh.nodes[c]
	if !exists {
		fh.Add(v, c)
		return
	}
	node.value = v

	if node.parent != nil {
		if node.value > node.parent.value {
			return
		}

		if node.parent.parent != nil {
			// Only the not root nodes can be marked
			if node.parent.mark {
				fh.moveMarkedParentsToRoot(node.parent)
			} else {
				node.parent.mark = true
				node.parent.child = nil
			}
		}
	}

	fh.moveToRoot(node)
	node.mark = false
}

// Len Returns the total number of elements in the heap
func (fh *FibonacciHeap) Len() int {
	return fh.length
}

// Min Returns the element with the smallest score in the heap and the score
func (fh *FibonacciHeap) Min() (value float64, content interface{}) {
	if fh.min == nil {
		return
	}

	fh.length--

	value = fh.min.value
	content = fh.min.content

	delete(fh.nodes, content)

	if fh.min.rank > 1 {
		fh.min.child.parent = nil
		if fh.min.l != fh.min {
			fh.min.l.r = fh.min.child
			fh.min.r.l = fh.min.child.l
			fh.min.child.l.r = fh.min.r
			fh.min.child.l = fh.min.l
		} else {
			// We are on the last node of the roots
			fh.min = fh.min.child
		}
	} else {
		if fh.min.l == fh.min {
			// This is the last node
			fh.min = nil

			return
		}

		fh.min.l.r = fh.min.r
		fh.min.r.l = fh.min.l
	}

	init := true
	min := math.Inf(1)
	node := fh.min.r
	origin := node
	for node != origin || init {
		if min > node.value {
			min = node.value
			fh.min = node
		}
		node = node.r
		init = false
	}

	fh.rebalance()

	return
}

func (fh *FibonacciHeap) mergeNodes(parent *node, child *node) {
	// Remove the child from the current linked list
	child.l.r = child.r
	child.r.l = child.l

	if parent.child != nil {
		child.r = parent.child.r
		parent.child.r = child
		child.r.l = child
		child.l = parent.child
	} else {
		child.r = child
		child.l = child
	}

	parent.child = child
	child.parent = parent
	parent.rank += child.rank
}

func (fh *FibonacciHeap) print(from *node, deep int) {
	initial := true
	aux := from
	for aux != from || initial {
		fmt.Println(deep, "Value:", aux.value, "Rank:", aux.rank, "Content:", aux.content, "Marked:", aux.mark)
		if aux.child != nil {
			fh.print(aux.child, deep+1)
		}
		aux = aux.r
		initial = false
	}
}

func (fh *FibonacciHeap) rebalance() {
	balanced := false
balance:
	for !balanced {
		usedRanks := make(map[uint64]*node)

		node := fh.min
		first := true
		for !balanced || first {
			if _, ok := usedRanks[node.rank]; ok {
				if node.value < usedRanks[node.rank].value {
					fh.mergeNodes(node, usedRanks[node.rank])
				} else {
					fh.mergeNodes(usedRanks[node.rank], node)
				}

				continue balance
			}

			usedRanks[node.rank] = node
			node = node.r
			balanced = node == fh.min
			first = false
		}
	}
}

func (fh *FibonacciHeap) moveToRoot(n *node) {
	if n.parent != nil {
		if n.r != n {
			n.parent.rank -= n.rank
			n.parent.child = n.r
		} else {
			n.parent.child = nil
			n.parent.rank = 1
		}
	}

	n.r.l = n.l
	n.l.r = n.r

	n.r = fh.min.r
	n.l = fh.min
	fh.min.r.l = n
	fh.min.r = n
	n.parent = nil

	if n.value < fh.min.value {
		fh.min = n
	}
}

func (fh *FibonacciHeap) moveMarkedParentsToRoot(n *node) {
	if n.mark {
		fh.moveMarkedParentsToRoot(n.parent)
		n.mark = false
		fh.moveToRoot(n)
	}
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
	"reflect"
	"sort"
	"strconv"
)

var N, M int
var vertices = [200000]Vertex{}

type Edge struct {
	next   int
	weight int
}

type Vertex struct {
	id     int
	fromId int
	weight int
}

func (e1 Vertex) Less(e2 interface{}) bool {
	return e1.weight < e2.(Vertex).weight
}

var edges = [200000][]Edge{}

func main() {
	sc.Split(bufio.ScanWords)
	defer out.Flush() // Use printf

	// CODE
	N := nextInt()
	M := nextInt()
	for i := 0; i < M; i++ {
		i := nextInt()
		j := nextInt()
		w := nextInt()
		edges[i] = append(edges[i], Edge{j, w})
		edges[j] = append(edges[j], Edge{i, w})
	}
	for i := 1; i <= N; i++ {
		vertices[i].weight = -1
	}

	q := NewPriorityQueue()
	q.Push(Vertex{id: 1, fromId: -1, weight: 0})
	for q.Len() > 0 {
		v := q.Pop().(Vertex)
		if vertices[v.id].weight != -1 {
			continue
		}
		vertices[v.id] = v
		for _, e := range edges[v.id] {
			q.Push(Vertex{
				id:     e.next,
				fromId: v.id,
				weight: v.weight + e.weight})
		}
	}
	if vertices[N].weight == -1 {
		printf("-1\n")
		return
	}
	ans := []int{}
	id := N
	for id != -1 {
		ans = append(ans, id)
		id = vertices[id].fromId
	}
	for i := len(ans) - 1; i >= 0; i-- {
		printf("%d ", ans[i])
	}
	printf("\n")
}

// I/O {{{

var sc = bufio.NewScanner(os.Stdin)
var out = bufio.NewWriter(os.Stdout)

func nextStr() string {
	sc.Scan()
	return sc.Text()
}

func nextInt() int {
	a, _ := strconv.Atoi(nextStr())
	return a
}

func nextFloat64() float64 {
	a, _ := strconv.ParseFloat(nextStr(), 64)
	return a
}

func nextInts(n int) []int {
	ret := make([]int, n)
	for i := 0; i < n; i++ {
		ret[i] = nextInt()
	}
	return ret
}

func nextFloats(n int) []float64 {
	ret := make([]float64, n)
	for i := 0; i < n; i++ {
		ret[i] = nextFloat64()
	}
	return ret
}

func nextStrings(n int) []string {
	ret := make([]string, n)
	for i := 0; i < n; i++ {
		ret[i] = nextStr()
	}
	return ret
}
func printf(f string, a ...interface{}) {
	fmt.Fprintf(out, f, a...)
}

// }}}
// Math {{{
func maxInt(x int, y int) int {
	if x > y {
		return x
	}
	return y
}

func minInt(x int, y int) int {
	if x < y {
		return x
	}
	return y
}

// }}}
// {{{ dummy
func dummy() {
	fmt.Fprintf(out, "Hello, World\n")
	fmt.Fprintf(out, "%v", reflect.TypeOf(0))

	arr := []int{10, 9, 8, 7, 1}
	sort.Ints(arr)
	fmt.Fprintln(out, arr)
}

// }}}
// PriorityQueue {{{
// Usage:
// type Person struct {
// 	name string
// 	age  int
// }
//
// func (p1 Person) Less(p2 interface{}) bool {
// 	return p1.age < p2.(Person).age
// }
//
// func main() {
// 	sc.Split(bufio.ScanWords)
// 	defer out.Flush() // Use printf
//
// 	// CODE
// 	q := NewPriorityQueue()
// 	q.Push(Person{name: "B", age: 11})
// 	q.Push(Person{name: "A", age: 10})
// 	q.Push(Person{name: "C", age: 12})
//
// 	for q.Len() > 0 {
// 		p := q.Pop().(Person)
// 		printf("%s %d\n", p.name, p.age)
// 	}
// }
func NewPriorityQueue() *PriorityQueue {
	q := &PriorityQueue{s: new(sorter)}
	heap.Init(q.s)
	return q
}

func (q *PriorityQueue) Pop() Comparable {
	return heap.Pop(q.s).(Comparable)
}

func (q *PriorityQueue) Top() Comparable {
	if len(*q.s) > 0 {
		return (*q.s)[0].(Comparable)
	}
	return nil
}

func (q *PriorityQueue) Fix(x Comparable, i int) {
	(*q.s)[i] = x
	heap.Fix(q.s, i)
}

func (q *PriorityQueue) Remove(i int) Comparable {
	return heap.Remove(q.s, i).(Comparable)
}

func (q *PriorityQueue) Len() int {
	return q.s.Len()
}

type Comparable interface {
	Less(other interface{}) bool
}

type sorter []Comparable

func (s *sorter) Push(x interface{}) {
	*s = append(*s, x.(Comparable))
}

func (s *sorter) Pop() interface{} {
	n := len(*s)
	if n > 0 {
		x := (*s)[n-1]
		*s = (*s)[0 : n-1]
		return x
	}
	return nil
}

func (s *sorter) Len() int {
	return len(*s)
}

func (s *sorter) Less(i, j int) bool {
	return (*s)[i].Less((*s)[j])
}

func (s *sorter) Swap(i, j int) {
	(*s)[i], (*s)[j] = (*s)[j], (*s)[i]
}

// Define priority queue struct
type PriorityQueue struct {
	s *sorter
}

func (q *PriorityQueue) Push(x Comparable) {
	heap.Push(q.s, x)
}

// }}}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
	"reflect"
	"sort"
)

var N, M int
var vertices = [200000]Vertex{}

type Edge struct {
	next   int
	weight int
}

type Vertex struct {
	id     int
	fromId int
	weight int
}

func (e1 Vertex) Less(e2 interface{}) bool {
	return e1.weight < e2.(Vertex).weight
}

var edges = [200000][]Edge{}

func main() {
	defer writer.Flush() // Use printf

	// CODE
	scanf("%d %d\n", &N, &M)
	for i := 0; i < M; i++ {
		var i, j, w int
		scanf("%d %d %d\n", &i, &j, &w)
		edges[i] = append(edges[i], Edge{j, w})
		edges[j] = append(edges[j], Edge{i, w})
	}
	for i := 1; i <= N; i++ {
		vertices[i].weight = -1
	}

	q := NewPriorityQueue()
	q.Push(Vertex{id: 1, fromId: -1, weight: 0})
	for q.Len() > 0 {
		v := q.Pop().(Vertex)
		if vertices[v.id].weight != -1 {
			continue
		}
		vertices[v.id] = v
		for _, e := range edges[v.id] {
			q.Push(Vertex{
				id:     e.next,
				fromId: v.id,
				weight: v.weight + e.weight})
		}
	}
	if vertices[N].weight == -1 {
		printf("-1\n")
		return
	}
	ans := []int{}
	id := N
	for id != -1 {
		ans = append(ans, id)
		id = vertices[id].fromId
	}
	for i := len(ans) - 1; i >= 0; i-- {
		printf("%d ", ans[i])
	}
	printf("\n")
}

// I/O {{{
var reader *bufio.Reader = bufio.NewReader(os.Stdin)
var writer *bufio.Writer = bufio.NewWriter(os.Stdout)

func printf(f string, a ...interface{}) { fmt.Fprintf(writer, f, a...) }
func scanf(f string, a ...interface{})  { fmt.Fscanf(reader, f, a...) }

// }}}
// Math {{{
func maxInt(x int, y int) int {
	if x > y {
		return x
	}
	return y
}

func minInt(x int, y int) int {
	if x < y {
		return x
	}
	return y
}

// }}}
// {{{ dummy
func dummy() {
	fmt.Printf("Hello, World\n")
	fmt.Printf("%v", reflect.TypeOf(0))

	arr := []int{10, 9, 8, 7, 1}
	sort.Ints(arr)
	fmt.Println(arr)
}

// }}}
// PriorityQueue {{{
// Usage:
// type Person struct {
// 	name string
// 	age  int
// }
//
// func (p1 Person) Less(p2 interface{}) bool {
// 	return p1.age < p2.(Person).age
// }
//
// func main() {
// 	sc.Split(bufio.ScanWords)
// 	defer out.Flush() // Use printf
//
// 	// CODE
// 	q := NewPriorityQueue()
// 	q.Push(Person{name: "B", age: 11})
// 	q.Push(Person{name: "A", age: 10})
// 	q.Push(Person{name: "C", age: 12})
//
// 	for q.Len() > 0 {
// 		p := q.Pop().(Person)
// 		printf("%s %d\n", p.name, p.age)
// 	}
// }
func NewPriorityQueue() *PriorityQueue {
	q := &PriorityQueue{s: new(sorter)}
	heap.Init(q.s)
	return q
}

func (q *PriorityQueue) Pop() Comparable {
	return heap.Pop(q.s).(Comparable)
}

func (q *PriorityQueue) Top() Comparable {
	if len(*q.s) > 0 {
		return (*q.s)[0].(Comparable)
	}
	return nil
}

func (q *PriorityQueue) Fix(x Comparable, i int) {
	(*q.s)[i] = x
	heap.Fix(q.s, i)
}

func (q *PriorityQueue) Remove(i int) Comparable {
	return heap.Remove(q.s, i).(Comparable)
}

func (q *PriorityQueue) Len() int {
	return q.s.Len()
}

type Comparable interface {
	Less(other interface{}) bool
}

type sorter []Comparable

func (s *sorter) Push(x interface{}) {
	*s = append(*s, x.(Comparable))
}

func (s *sorter) Pop() interface{} {
	n := len(*s)
	if n > 0 {
		x := (*s)[n-1]
		*s = (*s)[0 : n-1]
		return x
	}
	return nil
}

func (s *sorter) Len() int {
	return len(*s)
}

func (s *sorter) Less(i, j int) bool {
	return (*s)[i].Less((*s)[j])
}

func (s *sorter) Swap(i, j int) {
	(*s)[i], (*s)[j] = (*s)[j], (*s)[i]
}

// Define priority queue struct
type PriorityQueue struct {
	s *sorter
}

func (q *PriorityQueue) Push(x Comparable) {
	heap.Push(q.s, x)
}

// }}}

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pair struct {
	x int64
	y int
}
type pairHeap []pair

func (h pairHeap) Len() int              { return len(h) }
func (h pairHeap) Less(i, j int) bool    { return h[i].x < h[j].x }
func (h pairHeap) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *pairHeap) Push(v interface{})   { *h = append(*h, v.(pair)) }
func (h *pairHeap) Pop() (v interface{}) { n := len(*h); *h, v = (*h)[:n-1], (*h)[n-1]; return }

type neighbor struct {
	vertex int
	weight int
}

type graph struct {
	size    int
	edges   [][]neighbor
	visited []bool
}

func (g *graph) add(from, to int, weight int) {
	g.edges[from] = append(g.edges[from], neighbor{to, weight})
}

func (g *graph) addBoth(from, to int, weight int) {
	g.add(from, to, weight)
	if from != to {
		g.add(to, from, weight)
	}
}

func (g *graph) shortestPaths(start int) (dist []int64, parents []int) {
	const inf int64 = 1e18
	dist = make([]int64, g.size+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[start] = 0
	parents = make([]int, g.size+1)
	for i := range parents {
		parents[i] = -1
	}

	h := &pairHeap{}
	Push(h, pair{0, start})
	for h.Len() > 0 {
		p := Pop(h).(pair)
		v := p.y
		if g.visited[v] {
			continue
		}
		g.visited[v] = true
		for _, e := range g.edges[v] {
			w := e.vertex
			if newDist := dist[v] + int64(e.weight); newDist < dist[w] {
				dist[w] = newDist
				parents[w] = v
				Push(h, pair{newDist, w})
			}
		}
	}
	return
}

// github.com/EndlessCheng/codeforces-go
func Sol20C(reader io.Reader, writer io.Writer) {
	in := bufio.NewReader(reader)
	out := bufio.NewWriter(writer)
	defer out.Flush()

	var n, m int
	Fscan(in, &n, &m)
	g := &graph{
		size:    n,
		edges:   make([][]neighbor, n+1),
		visited: make([]bool, n+1),
	}
	for i := 0; i < m; i++ {
		var v, w, weight int
		Fscan(in, &v, &w, &weight)
		g.addBoth(v, w, weight)
	}

	dist, parents := g.shortestPaths(1)
	const inf int64 = 1e18
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	path := []int{}
	for v := n; v != -1; v = parents[v] {
		path = append(path, v)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() {
	Sol20C(os.Stdin, os.Stdout)
}

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pr struct {
	d int64
	v int
}
type hp []pr

func (h hp) Len() int              { return len(h) }
func (h hp) Less(i, j int) bool    { return h[i].d < h[j].d }
func (h hp) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{})   { *h = append(*h, v.(pr)) }
func (h *hp) Pop() (v interface{}) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }

// github.com/EndlessCheng/codeforces-go
func CF20C(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type edge struct {
		to int
		w  int64
	}

	var n, m, v, w int
	var weight int64
	Fscan(in, &n, &m)
	g := make([][]edge, n+1)
	for ; m > 0; m-- {
		Fscan(in, &v, &w, &weight)
		g[v] = append(g[v], edge{w, weight})
		g[w] = append(g[w], edge{v, weight})
	}

	const inf int64 = 1e18
	dist := make([]int64, n+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[1] = 0
	fa := make([]int, n+1)
	h := hp{{0, 1}}
	for len(h) > 0 {
		p := Pop(&h).(pr)
		d, v := p.d, p.v
		if dist[v] < d {
			continue
		}
		for _, e := range g[v] {
			w := e.to
			if newD := d + e.w; newD < dist[w] {
				dist[w] = newD
				fa[w] = v
				Push(&h, pr{newD, w})
			}
		}
	}
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	path := []int{}
	for x := n; x > 0; x = fa[x] {
		path = append(path, x)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() { CF20C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pair struct {
	d int64
	v int
}
type hp []pair

func (h hp) Len() int              { return len(h) }
func (h hp) Less(i, j int) bool    { return h[i].d < h[j].d }
func (h hp) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{})   { *h = append(*h, v.(pair)) }
func (h *hp) Pop() (v interface{}) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }

// github.com/EndlessCheng/codeforces-go
func CF20C(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type edge struct {
		to int
		w  int64
	}

	var n, m, v, w int
	var weight int64
	Fscan(in, &n, &m)
	g := make([][]edge, n+1)
	for ; m > 0; m-- {
		Fscan(in, &v, &w, &weight)
		g[v] = append(g[v], edge{w, weight})
		g[w] = append(g[w], edge{v, weight})
	}

	const inf int64 = 1e18
	dist := make([]int64, n+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[1] = 0
	fa := make([]int, n+1)
	h := hp{{0, 1}}
	for len(h) > 0 {
		p := Pop(&h).(pair)
		d, v := p.d, p.v
		for _, e := range g[v] {
			w := e.to
			if newD := d + e.w; newD < dist[w] {
				dist[w] = newD
				fa[w] = v
				Push(&h, pair{newD, w})
			}
		}
	}
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	path := []int{}
	for x := n; x > 0; x = fa[x] {
		path = append(path, x)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() { CF20C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pair struct {
	d int64
	v int
}
type hp []pair

func (h hp) Len() int              { return len(h) }
func (h hp) Less(i, j int) bool    { return h[i].d < h[j].d }
func (h hp) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{})   { *h = append(*h, v.(pair)) }
func (h *hp) Pop() (v interface{}) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }

// github.com/EndlessCheng/codeforces-go
func CF20C(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type edge struct {
		to int
		w  int64
	}

	var n, m, v, w int
	var weight int64
	Fscan(in, &n, &m)
	g := make([][]edge, n+1)
	for ; m > 0; m-- {
		Fscan(in, &v, &w, &weight)
		g[v] = append(g[v], edge{w, weight})
		g[w] = append(g[w], edge{v, weight})
	}

	const inf int64 = 1e18
	dist := make([]int64, n+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[1] = 0
	fa := make([]int, n+1)
	h := hp{{0, 1}}
	for len(h) > 0 {
		p := Pop(&h).(pair)
		d, v := p.d, p.v
		if dist[v] != d {
			continue
		}
		for _, e := range g[v] {
			w := e.to
			if newD := d + e.w; newD < dist[w] {
				dist[w] = newD
				fa[w] = v
				Push(&h, pair{newD, w})
			}
		}
	}
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	path := []int{}
	for x := n; x > 0; x = fa[x] {
		path = append(path, x)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() { CF20C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := 12345
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int, MAX)
	pred = make([]int, MAX)
	visited = make([]bool, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	var ans []int
	o, oo := n, n
	for o != 0 {
		ans = append(ans, o)
		oo = o
		o = pred[o]
	}
	if oo != 1 {
		O("-1\n")
	} else {
		for i := len(ans) - 1; i >= 0; i-- {
			delim := " "
			if i == 0 {
				delim = "\n"
			}
			O(ans[i], delim)
		}
	}
}

var adj [][]*Edge
var dist, pred []int
var visited []bool

var inf int = 2e9

func dijkstra(src, n int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if visited[u.vertex] {
			continue
		}
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if visited[aj.to] || aj.weight+u.dist >= dist[aj.to] {
				continue
			}
			dist[aj.to] = aj.weight + u.dist
			pred[aj.to] = u.vertex
			pq.Push(&Node{
				vertex: aj.to,
				dist:   dist[aj.to],
			})

		}
	}
}

type Node struct {
	vertex int
	dist   int
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist > pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	visited = make([]bool, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []int64
var visited []bool
var pred []int

var inf int64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				if !visited[aj.to] {
					pq.Push(&Node{
						vertex: aj.to,
						dist:   dist[aj.to],
					})
				}
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	visited = make([]bool, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []int64
var visited []bool
var pred []int

var inf int64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if !visited[u.vertex] {
			visited[u.vertex] = true
			for _, aj := range adj[u.vertex] {
				if int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
					dist[aj.to] = int64(aj.weight) + dist[u.vertex]
					pred[aj.to] = u.vertex
					pq.Push(&Node{
						vertex: aj.to,
						dist:   dist[aj.to],
					})
				}
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pr struct { d int64; v int }
type hp []pr

func (h hp) Len() int              { return len(h) }
func (h hp) Less(i, j int) bool    { return h[i].d < h[j].d }
func (h hp) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{})   { *h = append(*h, v.(pr)) }
func (h *hp) Pop() (v interface{}) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }

// github.com/EndlessCheng/codeforces-go
func CF20C(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type edge struct { to int; w int64 }

	var n, m, v, w int
	var weight int64
	Fscan(in, &n, &m)
	g := make([][]edge, n+1)
	for ; m > 0; m-- {
		Fscan(in, &v, &w, &weight)
		g[v] = append(g[v], edge{w, weight})
		g[w] = append(g[w], edge{v, weight})
	}

	const inf int64 = 1e18
	dist := make([]int64, n+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[1] = 0
	fa := make([]int, n+1)
	h := hp{{0, 1}}
	for len(h) > 0 {
		p := Pop(&h).(pr)
		d, v := p.d, p.v
		if dist[v] < d {
			continue
		}
		for _, e := range g[v] {
			w := e.to
			if newD := d + e.w; newD < dist[w] {
				dist[w] = newD
				fa[w] = v
				Push(&h, pr{newD, w})
			}
		}
	}

	path := []int{}
	for x := n; x > 0; x = fa[x] {
		path = append(path, x)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() { CF20C(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "container/heap"
	. "fmt"
	"io"
	"os"
)

type pair struct {
	x, y int
}
type pairHeap []pair

func (h pairHeap) Len() int              { return len(h) }
func (h pairHeap) Less(i, j int) bool    { return h[i].x < h[j].x }
func (h pairHeap) Swap(i, j int)         { h[i], h[j] = h[j], h[i] }
func (h *pairHeap) Push(v interface{})   { *h = append(*h, v.(pair)) }
func (h *pairHeap) Pop() (v interface{}) { n := len(*h); *h, v = (*h)[:n-1], (*h)[n-1]; return }

type neighbor struct {
	vertex int
	weight int
}

type graph struct {
	size    int
	edges   [][]neighbor
	visited []bool
}

func (g *graph) add(from, to int, weight int) {
	g.edges[from] = append(g.edges[from], neighbor{to, weight})
}

func (g *graph) addBoth(from, to int, weight int) {
	g.add(from, to, weight)
	if from != to {
		g.add(to, from, weight)
	}
}

func (g *graph) shortestPaths(start int) (dist []int, parents []int) {
	const inf int = 1e9
	dist = make([]int, g.size+1)
	for i := range dist {
		dist[i] = inf
	}
	dist[start] = 0
	parents = make([]int, g.size+1)
	for i := range parents {
		parents[i] = -1
	}

	h := &pairHeap{}
	Push(h, pair{0, start})
	for h.Len() > 0 {
		p := Pop(h).(pair)
		v := p.y
		if g.visited[v] {
			continue
		}
		g.visited[v] = true
		for _, e := range g.edges[v] {
			w := e.vertex
			if newDist := dist[v] + e.weight; newDist < dist[w] {
				dist[w] = newDist
				parents[w] = v
				Push(h, pair{newDist, w})
			}
		}
	}
	return
}

// github.com/EndlessCheng/codeforces-go
func Sol20C(reader io.Reader, writer io.Writer) {
	in := bufio.NewReader(reader)
	out := bufio.NewWriter(writer)
	defer out.Flush()

	var n, m int
	Fscan(in, &n, &m)
	g := &graph{
		size:    n,
		edges:   make([][]neighbor, n+1),
		visited: make([]bool, n+1),
	}
	for i := 0; i < m; i++ {
		var v, w, weight int
		Fscan(in, &v, &w, &weight)
		g.addBoth(v, w, weight)
	}

	dist, parents := g.shortestPaths(1)
	const inf int = 1e9
	if dist[n] == inf {
		Fprint(out, -1)
		return
	}
	path := []int{}
	for v := n; v != -1; v = parents[v] {
		path = append(path, v)
	}
	for i := len(path) - 1; i >= 0; i-- {
		Fprint(out, path[i], " ")
	}
}

func main() {
	Sol20C(os.Stdin, os.Stdout)
}

package main

import (
	"fmt"
	"strconv"
)

type Graph struct {
	edges          Edges
	startingIdxFor map[string]int
	endingIdxFor   map[string]int
	dist           map[string]float64
}

func (g *Graph) add(u, v string, w float64) {
	g.edges = append(g.edges, &Edge{u, v, w})
	//g.edges = append(g.edges, &Edge{v, u, w}) roads are directed
}

type GraphWithMaps struct {
	graph map[string][]*Edge
	dist  map[string]float64
	path  map[string]string
}

type priorityQueue []distanceNode

// Init establishes the heap invariants required by the other routines in this package.
// Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// The complexity is O(n) where n = h.Len().
func Init(pq *priorityQueue) {
	// heapify
	n := len(priorityQueue{})
	for i := n/2 - 1; i >= 0; i-- {
		down(pq, i, n)
	}
}

// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(pq *priorityQueue, dn distanceNode) {
	*pq = append(*pq, dn)
	up(pq, len(*pq)-1)
}

// Pop removes and returns the minimum element (according to Less) from the heap.
// The complexity is O(log n) where n = h.Len().
// Pop is equivalent to Remove(h, 0).
func Pop(pq *priorityQueue) distanceNode {
	n := len(*pq) - 1
	(*pq)[0], (*pq)[n] = (*pq)[n], (*pq)[0]
	down(pq, 0, n)

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Remove removes and returns the element at index i from the heap.
// The complexity is O(log n) where n = h.Len().
func Remove(pq *priorityQueue, i int) distanceNode {
	n := len(*pq) - 1
	if n != i {
		(*pq)[i], (*pq)[n] = (*pq)[n], (*pq)[i]
		if !down(pq, i, n) {
			up(pq, i)
		}
	}

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log n) where n = h.Len().
func Fix(pq *priorityQueue, i int) {
	if !down(pq, i, len(*pq)) {
		up(pq, i)
	}
}

func up(pq *priorityQueue, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		j = i
	}
}

func down(pq *priorityQueue, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && (*pq)[j2].dist < (*pq)[j1].dist {
			j = j2 // = 2*i + 2  // right child
		}
		if !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		i = j
	}
	return i > i0
}

type Edges []*Edge

func (a Edges) Len() int           { return len(a) }
func (a Edges) Less(i, j int) bool { return a[i].u < a[j].u }
func (a Edges) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func NewGraph() *Graph {
	return &Graph{
		edges:          make([]*Edge, 0),
		startingIdxFor: make(map[string]int),
		endingIdxFor:   make(map[string]int),
		dist:           make(map[string]float64),
	}
}

func NewGraphWithMaps() *GraphWithMaps {
	return &GraphWithMaps{
		graph: make(map[string][]*Edge),
		dist:  make(map[string]float64),
		path:  make(map[string]string),
	}
}

func (g *GraphWithMaps) distInf() {
	for k, _ := range g.graph {
		g.dist[k] = infinity
	}
}

func (g *GraphWithMaps) connect(u, v string, weight float64, isDirectedEdge bool) {
	vEdges, ok := g.graph[u]
	if !ok {
		vEdges = []*Edge{}
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	} else {
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	}
	if !isDirectedEdge {
		uEdges, ok := g.graph[v]
		if !ok {
			uEdges = []*Edge{}
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		} else {
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		}
	}
}

type Edge struct {
	u, v string
	dist float64
}

type distanceNode struct {
	to   string
	dist float64
}

var infinity = 100000000000.0

func (g *Graph) DijkstraNoTarget(source string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		//for _, edge := range outgoingEdges {
		//	fmt.Printf("Outgoing edges from %s outgoing edge %s\n", vertex.to, edge.v)
		//}
		//fmt.Println()
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *Graph) DijkstraTarget(source, target string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraTarget(source, target string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
				g.path[outgoing.v] = vertex.to
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraNoTarget(source string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) printPath(source, target string) []string {
	computedPath := []string{}
	_, ok := g.path[target]
	if !ok {
		return computedPath
	}
	computedPath = append(computedPath, target)
	startFrom := target
	for {
		nextTo, _ := g.path[startFrom]
		if nextTo == source {
			computedPath = append(computedPath, source)
			return computedPath
		}
		computedPath = append(computedPath, nextTo)
		startFrom = nextTo
	}
}

func main() {
	g3 := NewGraphWithMaps()
	var n, m int
	fmt.Scanf("%d %d\n", &n, &m)
	for i := 0; i < m; i++ {
		var u, v, w int
		fmt.Scanf("%d %d %d", &u, &v, &w)
		g3.connect(strconv.Itoa(u), strconv.Itoa(v), float64(w), false)
	}
	g3.distInf()
	g3.DijkstraTarget(strconv.Itoa(1), strconv.Itoa(n))
	path := g3.printPath(strconv.Itoa(1), strconv.Itoa(n))
	for i := len(path) - 1; i >= 0; i-- {
		val, err := strconv.Atoi(path[i])
		if err != nil {
			panic(err)
		}
		fmt.Printf("%d ", val)
	}
}

package main

import (
	"fmt"
)

type Graph struct {
	edges          Edges
	startingIdxFor map[int]int
	endingIdxFor   map[int]int
	dist           map[int]float64
}

func (g *Graph) add(u, v int, w float64) {
	g.edges = append(g.edges, &Edge{u, v, w})
	//g.edges = append(g.edges, &Edge{v, u, w}) roads are directed
}

type GraphWithMaps struct {
	graph map[int][]*Edge
	dist  map[int]float64
	path  map[int]int
}

type priorityQueue []distanceNode

// Init establishes the heap invariants required by the other routines in this package.
// Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// The complexity is O(n) where n = h.Len().
func Init(pq *priorityQueue) {
	// heapify
	n := len(priorityQueue{})
	for i := n/2 - 1; i >= 0; i-- {
		down(pq, i, n)
	}
}

// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(pq *priorityQueue, dn distanceNode) {
	*pq = append(*pq, dn)
	up(pq, len(*pq)-1)
}

// Pop removes and returns the minimum element (according to Less) from the heap.
// The complexity is O(log n) where n = h.Len().
// Pop is equivalent to Remove(h, 0).
func Pop(pq *priorityQueue) distanceNode {
	n := len(*pq) - 1
	(*pq)[0], (*pq)[n] = (*pq)[n], (*pq)[0]
	down(pq, 0, n)

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Remove removes and returns the element at index i from the heap.
// The complexity is O(log n) where n = h.Len().
func Remove(pq *priorityQueue, i int) distanceNode {
	n := len(*pq) - 1
	if n != i {
		(*pq)[i], (*pq)[n] = (*pq)[n], (*pq)[i]
		if !down(pq, i, n) {
			up(pq, i)
		}
	}

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log n) where n = h.Len().
func Fix(pq *priorityQueue, i int) {
	if !down(pq, i, len(*pq)) {
		up(pq, i)
	}
}

func up(pq *priorityQueue, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		j = i
	}
}

func down(pq *priorityQueue, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && (*pq)[j2].dist < (*pq)[j1].dist {
			j = j2 // = 2*i + 2  // right child
		}
		if !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		i = j
	}
	return i > i0
}

type Edges []*Edge

func (a Edges) Len() int           { return len(a) }
func (a Edges) Less(i, j int) bool { return a[i].u < a[j].u }
func (a Edges) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func NewGraph() *Graph {
	return &Graph{
		edges:          make([]*Edge, 0),
		startingIdxFor: make(map[int]int),
		endingIdxFor:   make(map[int]int),
		dist:           make(map[int]float64),
	}
}

func NewGraphWithMaps() *GraphWithMaps {
	return &GraphWithMaps{
		graph: make(map[int][]*Edge),
		dist:  make(map[int]float64),
		path:  make(map[int]int),
	}
}

func (g *GraphWithMaps) distInf(u, v int) {
	g.dist[u] = infinity
	g.dist[v] = infinity
}

func (g *GraphWithMaps) connect(u, v int, weight float64, isDirectedEdge bool) {
	vEdges, ok := g.graph[u]
	if !ok {
		vEdges = []*Edge{}
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	} else {
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	}
	if !isDirectedEdge {
		uEdges, ok := g.graph[v]
		if !ok {
			uEdges = []*Edge{}
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		} else {
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		}
	}
}

type Edge struct {
	u, v int
	dist float64
}

type distanceNode struct {
	to   int
	dist float64
}

var infinity = 100000000000.0

func (g *Graph) DijkstraNoTarget(source int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		//for _, edge := range outgoingEdges {
		//	fmt.Printf("Outgoing edges from %s outgoing edge %s\n", vertex.to, edge.v)
		//}
		//fmt.Println()
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *Graph) DijkstraTarget(source, target int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraTarget(source, target int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	visited := make(map[int]bool)
	for len(pq) > 0 {
		vertex := Pop(&pq)
		_, ok := visited[vertex.to]
		if ok {
			continue
		}
		visited[vertex.to] = true
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			_, ok := visited[outgoing.v]
			if !ok && g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
				g.path[outgoing.v] = vertex.to
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraNoTarget(source int) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) printPath(source, target int) []int {
	computedPath := []int{}
	_, ok := g.path[target]
	if !ok {
		computedPath = append(computedPath, -1)
		return computedPath
	}
	computedPath = append(computedPath, target)
	startFrom := target
	for {
		nextTo, ok := g.path[startFrom]
		if !ok {
			break
		}
		if nextTo == source {
			computedPath = append(computedPath, source)
			return computedPath
		}
		computedPath = append(computedPath, nextTo)
		startFrom = nextTo
	}
	computedPath = append(computedPath, -1)
	return computedPath
}

func main() {
	g3 := NewGraphWithMaps()
	var n, m int
	fmt.Scanf("%d %d\n", &n, &m)
	for i := 0; i < m; i++ {
		var u, v, w int
		fmt.Scanf("%d %d %d\n", &u, &v, &w)
		g3.connect(u, v, float64(w), true)
		g3.distInf(u, v)
	}
	g3.DijkstraTarget(1, n)
	path := g3.printPath(1, n)
	for i := len(path) - 1; i >= 0; i-- {
		fmt.Printf("%d ", path[i])
	}
}

package main

import (
	"fmt"
	"strconv"
)

type Graph struct {
	edges          Edges
	startingIdxFor map[string]int
	endingIdxFor   map[string]int
	dist           map[string]float64
}

func (g *Graph) add(u, v string, w float64) {
	g.edges = append(g.edges, &Edge{u, v, w})
	//g.edges = append(g.edges, &Edge{v, u, w}) roads are directed
}

type GraphWithMaps struct {
	graph map[string][]*Edge
	dist  map[string]float64
	path  map[string]string
}

type priorityQueue []distanceNode

// Init establishes the heap invariants required by the other routines in this package.
// Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// The complexity is O(n) where n = h.Len().
func Init(pq *priorityQueue) {
	// heapify
	n := len(priorityQueue{})
	for i := n/2 - 1; i >= 0; i-- {
		down(pq, i, n)
	}
}

// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(pq *priorityQueue, dn distanceNode) {
	*pq = append(*pq, dn)
	up(pq, len(*pq)-1)
}

// Pop removes and returns the minimum element (according to Less) from the heap.
// The complexity is O(log n) where n = h.Len().
// Pop is equivalent to Remove(h, 0).
func Pop(pq *priorityQueue) distanceNode {
	n := len(*pq) - 1
	(*pq)[0], (*pq)[n] = (*pq)[n], (*pq)[0]
	down(pq, 0, n)

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Remove removes and returns the element at index i from the heap.
// The complexity is O(log n) where n = h.Len().
func Remove(pq *priorityQueue, i int) distanceNode {
	n := len(*pq) - 1
	if n != i {
		(*pq)[i], (*pq)[n] = (*pq)[n], (*pq)[i]
		if !down(pq, i, n) {
			up(pq, i)
		}
	}

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log n) where n = h.Len().
func Fix(pq *priorityQueue, i int) {
	if !down(pq, i, len(*pq)) {
		up(pq, i)
	}
}

func up(pq *priorityQueue, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		j = i
	}
}

func down(pq *priorityQueue, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && (*pq)[j2].dist < (*pq)[j1].dist {
			j = j2 // = 2*i + 2  // right child
		}
		if !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		i = j
	}
	return i > i0
}

type Edges []*Edge

func (a Edges) Len() int           { return len(a) }
func (a Edges) Less(i, j int) bool { return a[i].u < a[j].u }
func (a Edges) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func NewGraph() *Graph {
	return &Graph{
		edges:          make([]*Edge, 0),
		startingIdxFor: make(map[string]int),
		endingIdxFor:   make(map[string]int),
		dist:           make(map[string]float64),
	}
}

func NewGraphWithMaps() *GraphWithMaps {
	return &GraphWithMaps{
		graph: make(map[string][]*Edge),
		dist:  make(map[string]float64),
		path:  make(map[string]string),
	}
}

func (g *GraphWithMaps) distInf() {
	for k, _ := range g.graph {
		g.dist[k] = infinity
	}
}

func (g *GraphWithMaps) connect(u, v string, weight float64, isDirectedEdge bool) {
	vEdges, ok := g.graph[u]
	if !ok {
		vEdges = []*Edge{}
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	} else {
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	}
	if !isDirectedEdge {
		uEdges, ok := g.graph[v]
		if !ok {
			uEdges = []*Edge{}
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		} else {
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		}
	}
}

type Edge struct {
	u, v string
	dist float64
}

type distanceNode struct {
	to   string
	dist float64
}

var infinity = 100000000000.0

func (g *Graph) DijkstraNoTarget(source string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		//for _, edge := range outgoingEdges {
		//	fmt.Printf("Outgoing edges from %s outgoing edge %s\n", vertex.to, edge.v)
		//}
		//fmt.Println()
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *Graph) DijkstraTarget(source, target string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraTarget(source, target string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	visited := make(map[string]bool)
	for len(pq) > 0 {
		vertex := Pop(&pq)
		_, ok := visited[vertex.to]
		if ok {
			continue
		}
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
				g.path[outgoing.v] = vertex.to
				visited[outgoing.v] = true
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraNoTarget(source string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) printPath(source, target string) []string {
	computedPath := []string{}
	_, ok := g.path[target]
	if !ok {
		computedPath = append(computedPath, "-1")
		return computedPath
	}
	computedPath = append(computedPath, target)
	startFrom := target
	for {
		nextTo, _ := g.path[startFrom]
		if nextTo == source {
			computedPath = append(computedPath, source)
			return computedPath
		}
		computedPath = append(computedPath, nextTo)
		startFrom = nextTo
	}
}

func main() {
	g3 := NewGraphWithMaps()
	var n, m int
	fmt.Scanf("%d %d\n", &n, &m)
	for i := 0; i < m; i++ {
		var u, v, w int
		fmt.Scanf("%d %d %d\n", &u, &v, &w)
		g3.connect(strconv.Itoa(u), strconv.Itoa(v), float64(w), false)
	}
	g3.distInf()
	g3.DijkstraTarget(strconv.Itoa(1), strconv.Itoa(n))
	path := g3.printPath(strconv.Itoa(1), strconv.Itoa(n))
	for i := len(path) - 1; i >= 0; i-- {
		val, err := strconv.Atoi(path[i])
		if err != nil {
			panic(err)
		}
		fmt.Printf("%d ", val)
	}

}

package main

import (
	"fmt"
	"strconv"
)

type Graph struct {
	edges          Edges
	startingIdxFor map[string]int
	endingIdxFor   map[string]int
	dist           map[string]float64
}

func (g *Graph) add(u, v string, w float64) {
	g.edges = append(g.edges, &Edge{u, v, w})
	//g.edges = append(g.edges, &Edge{v, u, w}) roads are directed
}

type GraphWithMaps struct {
	graph map[string][]*Edge
	dist  map[string]float64
	path  map[string]string
}

type priorityQueue []distanceNode

// Init establishes the heap invariants required by the other routines in this package.
// Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// The complexity is O(n) where n = h.Len().
func Init(pq *priorityQueue) {
	// heapify
	n := len(priorityQueue{})
	for i := n/2 - 1; i >= 0; i-- {
		down(pq, i, n)
	}
}

// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(pq *priorityQueue, dn distanceNode) {
	*pq = append(*pq, dn)
	up(pq, len(*pq)-1)
}

// Pop removes and returns the minimum element (according to Less) from the heap.
// The complexity is O(log n) where n = h.Len().
// Pop is equivalent to Remove(h, 0).
func Pop(pq *priorityQueue) distanceNode {
	n := len(*pq) - 1
	(*pq)[0], (*pq)[n] = (*pq)[n], (*pq)[0]
	down(pq, 0, n)

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Remove removes and returns the element at index i from the heap.
// The complexity is O(log n) where n = h.Len().
func Remove(pq *priorityQueue, i int) distanceNode {
	n := len(*pq) - 1
	if n != i {
		(*pq)[i], (*pq)[n] = (*pq)[n], (*pq)[i]
		if !down(pq, i, n) {
			up(pq, i)
		}
	}

	t := *pq
	var d distanceNode
	d, *pq = t[len(t)-1], t[:len(t)-1]
	return d
}

// Fix re-establishes the heap ordering after the element at index i has changed its value.
// Changing the value of the element at index i and then calling Fix is equivalent to,
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log n) where n = h.Len().
func Fix(pq *priorityQueue, i int) {
	if !down(pq, i, len(*pq)) {
		up(pq, i)
	}
}

func up(pq *priorityQueue, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		j = i
	}
}

func down(pq *priorityQueue, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && (*pq)[j2].dist < (*pq)[j1].dist {
			j = j2 // = 2*i + 2  // right child
		}
		if !((*pq)[j].dist < (*pq)[i].dist) {
			break
		}
		(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
		i = j
	}
	return i > i0
}

type Edges []*Edge

func (a Edges) Len() int           { return len(a) }
func (a Edges) Less(i, j int) bool { return a[i].u < a[j].u }
func (a Edges) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func NewGraph() *Graph {
	return &Graph{
		edges:          make([]*Edge, 0),
		startingIdxFor: make(map[string]int),
		endingIdxFor:   make(map[string]int),
		dist:           make(map[string]float64),
	}
}

func NewGraphWithMaps() *GraphWithMaps {
	return &GraphWithMaps{
		graph: make(map[string][]*Edge),
		dist:  make(map[string]float64),
		path:  make(map[string]string),
	}
}

func (g *GraphWithMaps) distInf() {
	for k, _ := range g.graph {
		g.dist[k] = infinity
	}
}

func (g *GraphWithMaps) connect(u, v string, weight float64, isDirectedEdge bool) {
	vEdges, ok := g.graph[u]
	if !ok {
		vEdges = []*Edge{}
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	} else {
		vEdges = append(vEdges, &Edge{
			u:    u,
			v:    v,
			dist: weight,
		})
		g.graph[u] = vEdges
	}
	if !isDirectedEdge {
		uEdges, ok := g.graph[v]
		if !ok {
			uEdges = []*Edge{}
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		} else {
			uEdges = append(uEdges, &Edge{
				u:    v,
				v:    u,
				dist: weight,
			})
			g.graph[v] = uEdges
		}
	}
}

type Edge struct {
	u, v string
	dist float64
}

type distanceNode struct {
	to   string
	dist float64
}

var infinity = 100000000000.0

func (g *Graph) DijkstraNoTarget(source string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		//for _, edge := range outgoingEdges {
		//	fmt.Printf("Outgoing edges from %s outgoing edge %s\n", vertex.to, edge.v)
		//}
		//fmt.Println()
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *Graph) DijkstraTarget(source, target string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.edges[g.startingIdxFor[vertex.to]:g.endingIdxFor[vertex.to]]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraTarget(source, target string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		// this comes straight from
		// If we are only interested in a shortest path between vertices source and target, we can terminate the search after line 15 if u = target. Now we can read the shortest path from source to target by reverse iteration:
		//12      while Q is not empty:
		//13          u ← vertex in Q with min dist[u]
		//14
		//15          remove u from Q
		//16
		//17          for each neighbor v of u:           // only v that are still in Q
		//18              alt ← dist[u] + length(u, v)
		//19              if alt < dist[v]:
		//20                  dist[v] ← alt
		//21                  prev[v] ← u
		//22
		//23      return dist[], prev[]
		if vertex.to == target {
			return
		}
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
				g.path[outgoing.v] = vertex.to
			}
		}
	}
}

func (g *GraphWithMaps) DijkstraNoTarget(source string) {
	pq := priorityQueue{{to: source, dist: 0}}
	Init(&pq)
	g.dist[source] = 0
	for len(pq) > 0 {
		vertex := Pop(&pq)
		if vertex.dist > g.dist[vertex.to] {
			continue
		}
		outgoingEdges := g.graph[vertex.to]
		for _, outgoing := range outgoingEdges {
			if g.dist[vertex.to]+outgoing.dist < g.dist[outgoing.v] {
				g.dist[outgoing.v] = g.dist[vertex.to] + outgoing.dist
				Push(&pq, distanceNode{
					to:   outgoing.v,
					dist: g.dist[outgoing.v],
				})
			}
		}
	}
}

func (g *GraphWithMaps) printPath(source, target string) []string {
	computedPath := []string{}
	_, ok := g.path[target]
	if !ok {
		return computedPath
	}
	computedPath = append(computedPath, target)
	startFrom := target
	for {
		nextTo, _ := g.path[startFrom]
		if nextTo == source {
			computedPath = append(computedPath, source)
			return computedPath
		}
		computedPath = append(computedPath, nextTo)
		startFrom = nextTo
	}
}

func main() {
	g3 := NewGraphWithMaps()
	var n, m int
	fmt.Scanf("%d %d\n", &n, &m)
	for i := 0; i < m; i++ {
		var u, v, w int
		fmt.Scanf("%d %d %d\n", &u, &v, &w)
		g3.connect(strconv.Itoa(u), strconv.Itoa(v), float64(w), false)
	}
	g3.distInf()
	g3.DijkstraTarget(strconv.Itoa(1), strconv.Itoa(n))
	path := g3.printPath(strconv.Itoa(1), strconv.Itoa(n))
	for i := len(path) - 1; i >= 0; i-- {
		val, err := strconv.Atoi(path[i])
		if err != nil {
			panic(err)
		}
		fmt.Printf("%d ", val)
	}

}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := 123456
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	pred = make([]int, MAX)
	visited = make([]bool, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	var ans []int
	o, oo := n, n
	for o != 0 {
		ans = append(ans, o)
		oo = o
		o = pred[o]
	}
	if oo != 1 {
		O("-1\n")
	} else {
		for i := len(ans) - 1; i >= 0; i-- {
			delim := " "
			if i == 0 {
				delim = "\n"
			}
			O(ans[i], delim)
		}
	}
}

var adj [][]*Edge
var dist []int64
var pred []int
var visited []bool

var inf int64 = 1e18

func dijkstra(src, n int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if visited[u.vertex] {
			continue
		}
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if visited[aj.to] || int64(aj.weight)+dist[u.vertex] >= dist[aj.to] {
				continue
			}
			dist[aj.to] = int64(aj.weight) + dist[u.vertex]
			pred[aj.to] = u.vertex
			pq.Push(&Node{
				vertex: aj.to,
				dist:   dist[aj.to],
			})

		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist > pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := 123456
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	pred = make([]int, MAX)
	visited = make([]bool, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	var ans []int
	o, oo := n, n
	for o != 0 {
		ans = append(ans, o)
		oo = o
		o = pred[o]
	}
	if oo != 1 {
		O("-1\n")
	} else {
		for i := len(ans) - 1; i >= 0; i-- {
			delim := " "
			if i == 0 {
				delim = "\n"
			}
			O(ans[i], delim)
		}
	}
}

var adj [][]*Edge
var dist []int64
var pred []int
var visited []bool

var inf int64 = 1e18

func dijkstra(src, n int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if visited[u.vertex] {
			continue
		}
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				pq.Push(&Node{
					vertex: aj.to,
					dist:   dist[aj.to],
				})
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	visited = make([]bool, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []int64
var visited []bool
var pred []int

var inf int64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src, dst int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if u.vertex == dst {
			return
		}
		if !visited[u.vertex] {
			visited[u.vertex] = true
			for _, aj := range adj[u.vertex] {
				if int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
					dist[aj.to] = int64(aj.weight) + dist[u.vertex]
					pred[aj.to] = u.vertex
					pq.Push(&Node{
						vertex: aj.to,
						dist:   dist[aj.to],
					})
				}
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := 123456
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	pred = make([]int, MAX)
	visited = make([]bool, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	var ans []int
	o, oo := n, n
	for o != 0 {
		ans = append(ans, o)
		oo = o
		o = pred[o]
	}
	if oo != 1 {
		O("-1\n")
	} else {
		for i := len(ans) - 1; i >= 0; i-- {
			delim := " "
			if i == 0 {
				delim = "\n"
			}
			O(ans[i], delim)
		}
	}
}

var adj [][]*Edge
var dist []int64
var pred []int
var visited []bool

var inf int64 = 1e18

func dijkstra(src, n int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if visited[u.vertex] {
			continue
		}
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if visited[aj.to] || int64(aj.weight)+u.dist >= dist[aj.to] {
				continue
			}
			dist[aj.to] = int64(aj.weight) + u.dist
			pred[aj.to] = u.vertex
			pq.Push(&Node{
				vertex: aj.to,
				dist:   dist[aj.to],
			})

		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist > pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []int64
var pred []int

var inf int64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src, dst int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		for _, aj := range adj[u.vertex] {
			if int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				if dst == aj.to {
					return
				}
				pq.Push(&Node{
					vertex: aj.to,
					dist:   dist[aj.to],
				})
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	visited = make([]bool, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []int64
var visited []bool
var pred []int

var inf int64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if !visited[aj.to] && int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				pq.Push(&Node{
					vertex: aj.to,
					dist:   dist[aj.to],
				})
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := 123456
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	pred = make([]int, MAX)
	visited = make([]bool, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	var ans []int
	o, oo := n, n
	for o != 0 {
		ans = append(ans, o)
		oo = o
		o = pred[o]
	}
	if oo != 1 {
		O("-1\n")
	} else {
		for i := len(ans) - 1; i >= 0; i-- {
			delim := " "
			if i == 0 {
				delim = "\n"
			}
			O(ans[i], delim)
		}
	}
}

var adj [][]*Edge
var dist []int64
var pred []int
var visited []bool

var inf int64 = 1e18

func dijkstra(src, n int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if visited[u.vertex] {
			continue
		}
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if !visited[aj.to] && int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				pq.Push(&Node{
					vertex: aj.to,
					dist:   dist[aj.to],
				})
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := 123456
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1, n)
	var ans []int
	o, oo := n, n
	for o != 0 {
		ans = append(ans, o)
		oo = o
		o = pred[o]
	}
	if oo != 1 {
		O("-1\n")
	} else {
		for i := len(ans) - 1; i >= 0; i-- {
			delim := " "
			if i == 0 {
				delim = "\n"
			}
			O(ans[i], delim)
		}
	}
}

var adj [][]*Edge
var dist []int64
var pred []int

var inf int64 = 1e18

func dijkstra(src, n int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if u.vertex == n {
			return
		}
		for _, aj := range adj[u.vertex] {
			if int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				pq.Push(&Node{
					vertex: aj.to,
					dist:   dist[aj.to],
				})
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	visited = make([]int, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []int64
var visited []int
var pred []int

var inf int64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		visited[u.vertex]++
		for _, aj := range adj[u.vertex] {
			if int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				if visited[aj.to] < 2 {
					pq.Push(&Node{
						vertex: aj.to,
						dist:   dist[aj.to],
					})
				}
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

func writeInt(i int) {
	if i < 0 {
		w.WriteByte('-')
		i = -i
	}
	if i < 10 {
		w.WriteByte(byte(i + 48))
		return
	}
	var tmp, count int
	tmp = i
	for tmp%10 == 0 {
		tmp /= 10
		count++
	}
	tmp = 0
	for i != 0 {
		tmp = tmp*10 + (i % 10)
		i /= 10
	}
	for tmp != 0 {
		w.WriteByte(byte((tmp % 10) + 48))
		tmp /= 10
	}
	for count > 0 {
		count--
		w.WriteByte('0')
	}
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := int(1e5) + 1
	m := readInt()
	adj = make([][]*Edge, MAX)
	dist = make([]int64, MAX)
	visited = make([]bool, MAX)
	pred = make([]int, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Edge{
			to:     v,
			weight: w,
		})
		adj[v] = append(adj[v], &Edge{
			to:     u,
			weight: w,
		})
	}
	dijkstra(1)
	if dist[n] == inf {
		writeInt(-1)
	} else {
		printPath(1, n)
	}
	w.WriteByte('\n')
}

var adj [][]*Edge
var dist []int64
var visited []bool
var pred []int

var inf int64 = 1e18

func printPath(i, j int) {
	if i != j {
		printPath(i, pred[j])
		w.WriteByte(' ')
	}
	writeInt(j)
}

func dijkstra(src int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		for _, aj := range adj[u.vertex] {
			if !visited[aj.to] && int64(aj.weight)+dist[u.vertex] < dist[aj.to] {
				dist[aj.to] = int64(aj.weight) + dist[u.vertex]
				pred[aj.to] = u.vertex
				pq.Push(&Node{
					vertex: aj.to,
					dist:   dist[aj.to],
				})
			}
		}
		visited[u.vertex] = true
	}
}

type Node struct {
	vertex int
	dist   int64
}

type Edge struct {
	to     int
	weight int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

func I(i ...interface{}) error {
	_, err := fmt.Fscan(r, i...)
	return err
}

func O(o ...interface{}) {
	fmt.Fprint(w, o...)
}

func readInt() int {
	var o bool
	var i int
	b, err := r.ReadByte()
	for err == nil {
		if b != ' ' && b != '\n' && b != '\r' {
			i = i*10 + int(b) - 48
			o = true
		} else if o {
			break
		}
		b, err = r.ReadByte()
	}
	return i
}

var (
	r *bufio.Reader
	w *bufio.Writer
)

func init() {
	if f, err := os.Open("in.goC"); err == nil {
		r = bufio.NewReader(f)
	} else {
		r = bufio.NewReader(os.Stdin)
	}
	w = bufio.NewWriter(os.Stdout)
}

func main() {
	var n int
	for I(&n) == nil {
		solve(n)
	}
	w.Flush()
}

func solve(n int) {
	MAX := 12345
	m := readInt()
	adj = make([][]*Node, MAX)
	dist = make([]int, MAX)
	pred = make([]int, MAX)
	visited = make([]bool, MAX)
	for i := 0; i < m; i++ {
		u, v, w := readInt(), readInt(), readInt()
		adj[u] = append(adj[u], &Node{
			vertex: v,
			dist:   w,
		})
		adj[v] = append(adj[u], &Node{
			vertex: u,
			dist:   w,
		})
	}
	dijkstra(1, n)
	var ans []int
	o, oo := n, n
	for o != 0 {
		ans = append(ans, o)
		oo = o
		o = pred[o]
	}
	if oo != 1 {
		O("-1\n")
	} else {
		for i := len(ans) - 1; i >= 0; i-- {
			delim := " "
			if i == 0 {
				delim = "\n"
			}
			O(ans[i], delim)
		}
	}
}

var adj [][]*Node
var dist, pred []int
var visited []bool

var inf int = 2e9

func dijkstra(src, n int) {
	for i := range dist {
		dist[i] = inf
	}
	dist[src] = 0
	var pq PriorityQueue
	heap.Init(&pq)
	pq.Push(&Node{
		vertex: src,
		dist:   0,
	})
	for pq.Len() > 0 {
		u := pq.Pop().(*Node)
		if visited[u.vertex] {
			continue
		}
		visited[u.vertex] = true
		for _, aj := range adj[u.vertex] {
			if visited[aj.vertex] {
				continue
			}
			if aj.dist+u.dist < dist[aj.vertex] {
				dist[aj.vertex] = aj.dist + u.dist
				pred[aj.vertex] = u.vertex
				pq.Push(&Node{
					vertex: aj.vertex,
					dist:   dist[aj.vertex],
				})
			}
		}
	}
}

type Node struct {
	vertex int
	dist   int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist > pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(*Node)
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}