Problem:
Score : 600 points

Problem Statement

Snuke's town has a subway system, consisting of N stations and M railway lines. The stations are numbered 1 through N. Each line is operated by a company. Each company has an identification number.

The i-th ( 1 \leq i \leq M ) line connects station p_i and q_i bidirectionally. There is no intermediate station. This line is operated by company c_i.

You can change trains at a station where multiple lines are available.

The fare system used in this subway system is a bit strange. When a passenger only uses lines that are operated by the same company, the fare is 1 yen (the currency of Japan). Whenever a passenger changes to a line that is operated by a different company from the current line, the passenger is charged an additional fare of 1 yen. In a case where a passenger who changed from some company A's line to another company's line changes to company A's line again, the additional fare is incurred again.

Snuke is now at station 1 and wants to travel to station N by subway. Find the minimum required fare.

Constraints

2 \leq N \leq 10^5

0 \leq M \leq 2×10^5

1 \leq p_i \leq N (1 \leq i \leq M)

1 \leq q_i \leq N (1 \leq i \leq M)

1 \leq c_i \leq 10^6 (1 \leq i \leq M)

p_i \neq q_i (1 \leq i \leq M)

Input

The input is given from Standard Input in the following format:

N M
p_1 q_1 c_1
:
p_M q_M c_M

Output

Print the minimum required fare. If it is impossible to get to station N by subway, print -1 instead.

Sample Input 1

3 3
1 2 1
2 3 1
3 1 2

Sample Output 1

1

Use company 1's lines: 1 → 2 → 3. The fare is 1 yen.

Sample Input 2

8 11
1 3 1
1 4 2
2 3 1
2 5 1
3 4 3
3 6 3
3 7 3
4 8 4
5 6 1
6 7 5
7 8 5

Sample Output 2

2

First, use company 1's lines: 1 → 3 → 2 → 5 → 6. Then, use company 5's lines: 6 → 7 → 8. The fare is 2 yen.

Sample Input 3

2 0

Sample Output 3

-1

Solution in C# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Contest
{
    class Scanner
    {
        private string[] line = new string[0];
        private int index = 0;
        public string Next()
        {
            if (line.Length <= index)
            {
                line = Console.ReadLine().Split(' ');
                index = 0;
            }
            var res = line[index];
            index++;
            return res;
        }
        public int NextInt()
        {
            return int.Parse(Next());
        }
        public long NextLong()
        {
            return long.Parse(Next());
        }
        public string[] Array()
        {
            line = Console.ReadLine().Split(' ');
            index = line.Length;
            return line;
        }
        public int[] IntArray()
        {
            var array = Array();
            var result = new int[array.Length];
            for (int i = 0; i < array.Length; i++)
            {
                result[i] = int.Parse(array[i]);
            }

            return result;
        }
        public long[] LongArray()
        {
            var array = Array();
            var result = new long[array.Length];
            for (int i = 0; i < array.Length; i++)
            {
                result[i] = long.Parse(array[i]);
            }

            return result;
        }
    }

    class PriorityQueue<T>
    {
        private readonly List<T> heap;
        private readonly Comparison<T> compare;
        private int size;
        public PriorityQueue() : this(Comparer<T>.Default) { }
        public PriorityQueue(IComparer<T> comparer) : this(16, comparer.Compare) { }
        public PriorityQueue(Comparison<T> comparison) : this(16, comparison) { }
        public PriorityQueue(int capacity, Comparison<T> comparison)
        {
            this.heap = new List<T>(capacity);
            this.compare = comparison;
        }
        public void Enqueue(T item)
        {
            this.heap.Add(item);
            var i = size++;
            while (i > 0)
            {
                var p = (i - 1) >> 1;
                if (compare(this.heap[p], item) <= 0)
                    break;
                this.heap[i] = heap[p];
                i = p;
            }
            this.heap[i] = item;

        }
        public T Dequeue()
        {
            var ret = this.heap[0];
            var x = this.heap[--size];
            var i = 0;
            while ((i << 1) + 1 < size)
            {
                var a = (i << 1) + 1;
                var b = (i << 1) + 2;
                if (b < size && compare(heap[b], heap[a]) < 0) a = b;
                if (compare(heap[a], x) >= 0)
                    break;
                heap[i] = heap[a];
                i = a;
            }
            heap[i] = x;
            heap.RemoveAt(size);
            return ret;
        }
        public T Peek() { return heap[0]; }
        public int Count { get { return size; } }
        public bool Any() { return size > 0; }
    }

    class Program
    {
        private int N;
        private int M;
        private int[] P, Q, C;

        private Dictionary<Sta, List<int>> L;
        private List<int>[] R;

        struct Sta
        {
            public int Num;
            public int Route;

            public Sta(int num, int route)
            {
                this.Num = num;
                this.Route = route;
            }
        }

        struct Node
        {
            public Sta Station;
            public int Fee;

            public Node(Sta sta, int fee)
            {
                this.Station = sta;
                this.Fee = fee;
            }
        }

        private void Scan()
        {
            var sc = new Scanner();
            N = sc.NextInt();
            M = sc.NextInt();
            P = new int[M];
            Q = new int[M];
            C = new int[M];



            for (int i = 0; i < M; i++)
            {
                P[i] = sc.NextInt() - 1;
                Q[i] = sc.NextInt() - 1;
                C[i] = sc.NextInt();
            }
        }

        public void Solve()
        {
            Scan();
            L = new Dictionary<Sta, List<int>>();
            R = new List<int>[N];
            for (int i = 0; i < N; i++)
            {
                R[i] = new List<int>();
            }
            for (int i = 0; i < M; i++)
            {
                Add(P[i], Q[i], C[i]);
                Add(Q[i], P[i], C[i]);
                AddSta(P[i], C[i]);
                AddSta(Q[i], C[i]);
            }

            var pq = new PriorityQueue<Node>((a, b) => a.Fee.CompareTo(b.Fee));
            var hs = new HashSet<Sta>();

            pq.Enqueue(new Node(new Sta(0, 0), 0));
            while (pq.Count > 0)
            {
                var n = pq.Dequeue();
                if (!hs.Add(n.Station))
                    continue;
                if (n.Station.Num == N - 1)
                {
                    Console.WriteLine(n.Fee);
                    return;
                }
                if (n.Station.Route == 0)
                {
                    foreach (var i in R[n.Station.Num])
                    {
                        pq.Enqueue(new Node(new Sta(n.Station.Num, i), n.Fee + 1));
                    }
                }

                else
                {
                    foreach (var i in L[n.Station])
                    {
                        pq.Enqueue(new Node(new Sta(i, n.Station.Route), n.Fee));
                    }
                    pq.Enqueue(new Node(new Sta(n.Station.Num, 0), n.Fee));
                }
            }

            Console.WriteLine(-1);
        }

        private void Add(int p, int q, int c)
        {
            Sta pos = new Sta(p, c);
            List<int> o;
            if (!L.TryGetValue(pos, out o))
            {
                L[pos] = new List<int>();
            }
            L[pos].Add(q);
        }

        private void AddSta(int p, int c)
        {
            R[p].Add(c);
        }


        static void Main(string[] args)
        {
            new Program().Solve();
        }
    }
}