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: Wrong Answer)

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

class Myon
{
    public Myon() { }
    public static int Main()
    {
        new Myon().calc();
        return 0;
    }

    Scanner cin;

    int N, M;
    int[] dist;
    List<Tuple<int, int>>[] es;
    Dictionary<long, int> dic = new Dictionary<long, int>();
    const int MAX = 9999999;

    int[] memo;

    public void calc()
    {
        cin = new Scanner();
        N = cin.nextInt();
        M = cin.nextInt();
        es = new List<Tuple<int, int>>[N];
        for (int i = 0; i < N; i++)
        {
            es[i] = new List<Tuple<int, int>>();
        }
        for (int i = 0; i < M; i++)
        {
            int p = cin.nextInt() - 1;
            int q = cin.nextInt() - 1;
            int c = cin.nextInt() - 1;
            es[p].Add(Tuple.Create(q, c));
            es[q].Add(Tuple.Create(p, c));
        }

        dist = new int[N];
        for (int i = 0; i < N; i++)
        {
            dist[i] = MAX;
        }
        dist[0] = 0;

        List<int> now = new List<int>();
        now.Add(0);
        int nowdist = 0;

        int memocnt = 1;
        memo = new int[N];

        while(now.Count != 0 && dist[N-1] == MAX)
        {
            nowdist++;
            List<int> next = new List<int>();
            Dictionary<int, List<int>> dl = new Dictionary<int, List<int>>();
            foreach (int s in now)
            {
                foreach (var p in es[s])
                {
                    int t = p.Item1;
                    int c = p.Item2;
                    if (dist[t] == MAX)
                    {
                        dist[t] = nowdist;
                        next.Add(t);
                    }
                    if(dist[t] == nowdist)
                    {
                        long hash = ((long)t << 31) + c;
                        if (!dic.ContainsKey(hash))
                        {
                            dic[hash] = 1;
                            if (!dl.ContainsKey(c))
                            {
                                dl[c] = new List<int>();
                            }
                            dl[c].Add(t);
                        }
                    }
                }
            }


            foreach (var item in dl)
            {
                int comp = item.Key;
                List<int> list = item.Value;
                Queue<int> q = new Queue<int>();
                memocnt++;
                foreach (var start in list)
                {
                    q.Enqueue(start);
                    next.Add(start);
                    memo[start] = memocnt;
                }

                while(q.Count != 0)
                {
                    int s = q.Dequeue();
                    foreach (var p in es[s])
                    {
                        int t = p.Item1;
                        int c = p.Item2;
                        if (c != comp) continue;

                        if (dist[t] == MAX)
                        {
                            dist[t] = nowdist;
                            memo[t] = memocnt;
                            q.Enqueue(t);
                        }
                        else if (dist[t] == nowdist && memo[t] != memocnt)
                        {
                            memo[t] = memocnt;
                            q.Enqueue(t);
                        }
                    }
                }


            }
            now = next;
        }
        if (dist[N - 1] == MAX) Console.WriteLine(-1);
        else Console.WriteLine(dist[N - 1]);

    }
    
}


class Scanner
{
    string[] s;
    int i;

    char[] cs = new char[] { ' ' };

    public Scanner()
    {
        s = new string[0];
        i = 0;
    }

    public string next()
    {
        while (i >= s.Length)
        {
            string st = Console.ReadLine();
            while (st == "") st = Console.ReadLine();
            s = st.Split(cs, StringSplitOptions.RemoveEmptyEntries);
            i = 0;
        }
        return s[i++];
    }

    public int nextInt()
    {
        return int.Parse(next());
    }

    public long nextLong()
    {
        return long.Parse(next());
    }

    public double nextDouble()
    {
        return double.Parse(next());
    }

}