You are given a weighted undirected graph. The vertices are enumerated from 1 to n. Your task is to find the shortest path between the vertex 1 and the vertex n.

The first line contains two integers n and m (2 ≤ n ≤ 105, 0 ≤ m ≤ 105), where n is the number of vertices and m is the number of edges. Following m lines contain one edge each in form ai, bi and wi (1 ≤ ai, bi ≤ n, 1 ≤ wi ≤ 106), where ai, bi are edge endpoints and wi is the length of the edge. It is possible that the graph has loops and multiple edges between pair of vertices.

Write the only integer -1 in case of no path. Write the shortest path in opposite case. If there are many solutions, print any of them.

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"
	"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"
)

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
}