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 Java7 (OpenJDK 1.7.0) (judge verdict: Wrong Answer)

import java.io.*;
import java.util.*;


public class Main {

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String buf;
		String[] input;
		int i;
		int N, M;
		int p;
		int q;
		int c;
		HashMap<Integer, ArrayList<Pair<Integer, Integer>>> station = new HashMap<Integer, ArrayList<Pair<Integer, Integer>>>();
		HashSet<Pair<Integer, Integer>> pq = new HashSet<Pair<Integer, Integer>>();
		Dijkstra<Pair<Integer, Integer>> dijkstra = new Dijkstra<Pair<Integer, Integer>>();

		buf = br.readLine();
		input = buf.split(" ");
		N = Integer.parseInt(input[0]);
		M = Integer.parseInt(input[1]);

		for(i=1;i<=N;i++) {
			station.put(i, new ArrayList<Pair<Integer, Integer>>());
		}

		for(i=0;i<M;i++) {
			buf = br.readLine();
			input = buf.split(" ");
			p = Integer.parseInt(input[0]);
			q = Integer.parseInt(input[1]);
			c = Integer.parseInt(input[2]);
			Pair<Integer, Integer> pair;
			if(p < q) {
				pair = new Pair<Integer, Integer>(p, q);
			} else {
				pair = new Pair<Integer, Integer>(q, p);
			}
			if(!pq.contains(pair)) pq.add(pair);
			Pair<Integer, Integer> pc = new Pair<Integer, Integer>(p, c);
			Pair<Integer, Integer> qc = new Pair<Integer, Integer>(q, c);
			if(!station.get(p).contains(pc)) station.get(p).add(pc);
			if(!station.get(q).contains(qc)) station.get(q).add(qc);
		}

		for(Pair<Integer, Integer> pair : pq) {
			for(Pair<Integer, Integer> u : station.get(pair.first)) {
				for(Pair<Integer, Integer> v : station.get(pair.second)) {
					if(u.second == v.second) {
						dijkstra.input(u, v, 0, true);
					}
				}
			}
		}

		for(i=1;i<=N;i++) {
			Pair<Integer, Integer> outside = new Pair<Integer, Integer>(i, -1);
			for(Pair<Integer, Integer> u : station.get(i)) {
				dijkstra.input(u, outside, 0, false);
				dijkstra.input(outside, u, 1, false);
			}
		}

		Pair<Integer, Integer> start = new Pair<Integer, Integer>(1, -1);
		Pair<Integer, Integer> end = new Pair<Integer, Integer>(N, -1);
		Pair<Integer, Pair<Integer, Integer>> ans = dijkstra.solve(start, end);

		if(ans.second == null) {
			System.out.println(-1);
		} else {
			System.out.println(ans.first);
		}
	}

}

class Dijkstra<E> {
	HashMap<E, Integer> d = new HashMap<E, Integer>();
	HashMap<E, E> prev = new HashMap<E, E>();
	TreeSet<Pair<E, Integer>> Q = new TreeSet<Pair<E, Integer>>(
			new Comparator<Pair<E, Integer>>() {
				@Override
				public int compare(Pair<E, Integer> o1, Pair<E, Integer> o2) {
					if(o1.second < o2.second) return -1;
					else if(o1.second > o2.second) return 1;
					else {
						if(o1.equals(o2)) return 0;
						else return 1;
					}
				}
			});
	HashMap<E, HashMap<E, Integer>> list = new HashMap<E, HashMap<E, Integer>>();

	Dijkstra() {

	}

	void input(E u, E v, int cost, boolean isDig) {
		if(!list.containsKey(u)) list.put(u, new HashMap<E, Integer>());
		list.get(u).put(v, cost);

		if(isDig) {
			if(!list.containsKey(v)) list.put(v, new HashMap<E, Integer>());
			list.get(v).put(u, cost);
		}
	}

	Pair<Integer, E> solve(E start, E end) {
		for(E node : list.keySet()) {
			d.put(node, node.equals(start) ? 0 : Integer.MAX_VALUE);
			prev.put(node, null);
			Q.add(new Pair<E, Integer>(node, d.get(node)));
		}

		while(!Q.isEmpty()) {
			E u = Q.pollFirst().first;
			int alt;
			for(E v : list.get(u).keySet()) {
				alt = d.get(u) + list.get(u).get(v);
				if(d.get(v) > alt) {
					d.put(v, alt);
					prev.put(v, u);
					Q.add(new Pair<E, Integer>(v, alt));
				}
			}
		}

		return new Pair<Integer, E>(d.get(end), prev.get(end));
	}
}

class Pair<F, S> {
    public final F first;
    public final S second;

    Pair (F first, S second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public boolean equals (Object obj) {
        if (! (obj instanceof Pair))
            return false;
        @SuppressWarnings("unchecked")
		Pair<F, S> pair = (Pair<F, S>) obj;
        return (first.equals (pair.first) && second.equals (pair.second));
    }

    @Override
    public int hashCode () {
        return first.hashCode () ^ second.hashCode ();
    }

    @Override
    public String toString() {
    	return "(" + first.toString() + "," + second.toString() + ")";
    }
}