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++14 (GCC 5.4.1) (judge verdict: Accepted)

/*************************************************
 *************************************************
 *************************************************
 *** _________________  |            |  |     /***
 ***         |          |            |  |    / ***
 ***         |          |            |  |   /  ***
 ***         |          |            |  |  /   ***
 ***         |          |            |  | /    ***
 ***         |          |____________|  |/  en ***
 ***         |          |            |  |\     ***
 ***         |          |            |  | \    ***
 *** _____   |          |            |  |  \   ***
 ***   |     |          |            |  |   \  ***
 ***   \     /          |            |  |    \ ***
 ***    \___/           |            |  |     \***
 *************************************************
 *************Written by: JiangHaoKai*************
 *************************************************/
#pragma GCC optimize(2)
#pragma G++ optimize(2)

//#include <bits/stdc++.h>
#include <cassert>
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <valarray>
#include <vector>
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <unordered_map>
#include <unordered_set>
//#include <conio.h>
//#include <windows.h>
using namespace std;

typedef long long LL;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef float fl;
typedef double ld;
typedef pair<int,int> pii;
#define ui(n) ((unsigned int)(n))
#define ll(n) ((long long)(n))
#define ull(n) ((unsigned long long)(n))
#define fl(n) ((float)(n))
#define ld(n) ((double)(n))
#define char(n) ((char)(n))
#define Bool(n) ((bool)(n))
#define fixpoint(n) fixed<<setprecision(n)
const int INF=1061109567;
const LL LINF=4557430888798830399;
#define PI 3.1415926535897932384626433832795028841971
#define MP make_pair
#define MT make_tuple
#define All(a) (a).begin(),(a).end()
#define pall(a) (a).rbegin(),(a).rend()
#define mod 1000000007
#define sz(a) ((int)(a).size())
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define repa(i,a,n) for(int i=a;i<n;i++)
#define repa1(i,a,n) for(int i=a;i<=n;i++)
#define repd(i,n) for(int i=n-1;i>=0;i--)
#define repd1(i,n) for(int i=n;i>=1;i--)
#define repda(i,n,a) for(int i=n;i>a;i--)
#define repda1(i,n,a) for(int i=n;i>=a;i--)
#define FOR(i,a,n,step) for(int i=a;i<n;i+=step)
#define repv(itr,v) for(__typeof((v).begin()) itr=(v).begin();itr!=(v).end();itr++)
#define repV(i,v) for(auto i:v)
#define repE(i,v) for(auto &i:v)
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x) MS(x,0)
#define MCP(x,y) memcpy(x,y,sizeof(y))
#define sqr(x) ((x)*(x))
#define filein(x) freopen(x,"r",stdin)
#define fileout(x) freopen(x,"w",stdout)
#define fileout2(filename,name) ofstream name(filename,ios::out)
#define filein2(filename,name) ifstream name(filename,ios::in)
#define file(filename,name) fstream name(filename,ios::in|ios::out)
#define Pause system("pause")
#define Cls system("cls")
#define fs first
#define sc second
#define PC(x) putchar(x)
#define GC(x) x=getchar()
#define Endl PC('\n')
#define SF scanf
#define PF printf

inline int Read()
{
    int X=0,w=0;char ch=0;while(!isdigit(ch)){w|=ch=='-';ch=getchar();}while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
	return w?-X:X;
}
inline void Write(int x){if(x<0)putchar('-'),x=-x;if(x>9)Write(x/10);putchar(x%10+'0');}

inline LL powmod(LL a,LL b){LL res=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
inline LL gcdll(LL a,LL b){return b?gcdll(b,a%b):a;}
const int dx[]={0,1,0,-1,1,-1,-1,1};
const int dy[]={1,0,-1,0,-1,-1,1,1};
/**************************************************************Begin***************************************************************/
const int maxn=100010,maxm=1000010;

struct UF
{
	int fa[maxm],Rank[maxm];
	
	inline void INIT(int n)
	{
		rep(i,n) fa[i]=i,Rank[i]=0;
	}
	
	inline void rem(int x)
	{
		fa[x]=x;
		Rank[x]=0;
	}
	
	inline int Find(int x)
	{
		if(x==fa[x]) return x; else return fa[x]=Find(fa[x]);
	}
	
	inline void unite(int x,int y)
	{
		x=Find(x);y=Find(y);
		
		if(x!=y)
		{
			if(Rank[x]<Rank[y]) fa[x]=y;
			else
			{
				fa[y]=x;
				if(Rank[x]==Rank[y]) Rank[x]++;
			}
		}
	}
	
	inline bool same(int x,int y)
	{
		return Find(x)==Find(y);
	}
};

int n,m,id[maxm],dist[maxm],siz;
UF uf;
vector<int> vec[maxm];
vector<pair<int,int> > color[maxm];
bool vis[maxm];
queue<int> q;

int main()
{
	SF("%d%d",&n,&m);
	rep(i,m)
	{
		int a,b,c;SF("%d%d%d",&a,&b,&c);
		color[c].push_back({a,b});
	}
	
	siz=n;
	rep1(i,maxm) if(!color[i].empty())
	{
		repV(j,color[i])
		{
			uf.rem(j.fs);
			uf.rem(j.sc);
			id[j.fs]=id[j.sc]=-1;
			vis[j.fs]=vis[j.sc]=0;
		}
		
		repV(j,color[i]) uf.unite(j.fs,j.sc);
		
		repV(j,color[i])
		{
			if(!vis[j.fs])
			{
				vis[j.fs]=1;
				int r=uf.Find(j.fs);
				
				if(id[r]==-1) id[r]=++siz;
				vec[j.fs].push_back(id[r]);
				vec[id[r]].push_back(j.fs);
			}
			
			if(!vis[j.sc])
			{
				vis[j.sc]=1;
				int r=uf.Find(j.sc);
				
				if(id[r]==-1) id[r]=++siz;
				vec[j.sc].push_back(id[r]);
				vec[id[r]].push_back(j.sc);
			}
		}
	}
	
	MS(dist,-1);
	dist[1]=0;
	q.push(1);
	
	while(!q.empty())
	{
		int x=q.front();q.pop();
		repV(i,vec[x]) if(dist[i]==-1) dist[i]=dist[x]+1,q.push(i);
	}
	
	if(dist[n]==-1) PF("-1"); else PF("%d",dist[n]/2);

	return 0;
}
/***************************************************************End****************************************************************/