#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>;
const int INF = 1e9;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
if (!(cin >> n >> m)) return 0;
vector<vector<pair<int,int>>> out(n+1); // out[u] = list of (v, color)
vector<tuple<int,int,int>> edges;
edges.reserve(m);
for (int i = 0; i < m; ++i) {
int u, v, c;
cin >> u >> v >> c;
edges.emplace_back(u,v,c);
out[u].push_back({v,c});
}
if (n == 1) { // already at destination
cout << 0 << '\n';
return 0;
}
// For each node v, collect set of incoming colors (colors of edges that end at v)
vector<unordered_map<int,int>> color_id(n+1);
color_id.assign(n+1, unordered_map<int,int>());
for (auto &t : edges) {
int u,v,c;
tie(u,v,c) = t;
if (color_id[v].find(c) == color_id[v].end()) {
int id = (int)color_id[v].size();
color_id[v][c] = id;
}
// Note: we don't need colors for u unless there is incoming edge to u
}
// assign global ids to each (v, color)
vector<int> base_index(n+1, 0); // base_index[v] = starting id for node v in dist array
int total_states = 0;
for (int v = 1; v <= n; ++v) {
base_index[v] = total_states;
total_states += (int)color_id[v].size();
}
if (total_states == 0) {
// no edge enters any node => impossible unless n==1 (handled)
cout << -1 << '\n';
return 0;
}
auto get_state = [&](int v, int color) -> int {
auto it = color_id[v].find(color);
if (it == color_id[v].end()) return -1;
return base_index[v] + it->second;
};
vector<int> dist(total_states, INF);
deque<int> dq;
// Initialize: from node 1 (no previous color), taking any outgoing edge (1->v,color)
// leads to state (v,color) with cost 0 (first edge never counts as a color-change).
for (auto &p : out[1]) {
int v = p.first;
int c = p.second;
int sid = get_state(v, c);
if (sid == -1) continue; // shouldn't happen but safe
if (dist[sid] > 0) {
dist[sid] = 0;
dq.push_front(sid);
}
}
// 0-1 BFS over states
while (!dq.empty()) {
int cur = dq.front(); dq.pop_front();
int curd = dist[cur];
// decode cur -> (u,color_prev)
// We need to know which node u this state belongs to and the color value.
// To decode, find node v such that base_index[v] <= cur < base_index[v] + color_id[v].size()
// We'll binary search over base_index since base_index is monotonic.
// Simpler: build reverse mapping arrays of state -> (node, color_value).
break;
}
// Because we need decode, rebuild reverse arrays:
vector<int> state_node(total_states), state_color(total_states);
for (int v = 1; v <= n; ++v) {
for (auto &kv : color_id[v]) {
int color = kv.first;
int idx = kv.second;
int sid = base_index[v] + idx;
state_node[sid] = v;
state_color[sid] = color;
}
}
// Reinitialize dist and deque, then run proper BFS
fill(dist.begin(), dist.end(), INF);
dq.clear();
for (auto &p : out[1]) {
int v = p.first, c = p.second;
int sid = get_state(v, c);
if (sid == -1) continue;
if (dist[sid] > 0) {
dist[sid] = 0;
dq.push_front(sid);
}
}
while (!dq.empty()) {
int cur = dq.front(); dq.pop_front();
int curd = dist[cur];
int u = state_node[cur];
int color_prev = state_color[cur];
// from (u, color_prev) try all outgoing edges (u -> v, c)
for (auto &e : out[u]) {
int v = e.first;
int c = e.second;
int nxt = get_state(v, c);
if (nxt == -1) continue; // state not present (shouldn't happen)
int add = (c == color_prev) ? 0 : 1;
if (dist[nxt] > curd + add) {
dist[nxt] = curd + add;
if (add == 0) dq.push_front(nxt);
else dq.push_back(nxt);
}
}
}
// answer = min dist over all states that correspond to node n
int best = INF;
if (!color_id[n].empty()) {
for (auto &kv : color_id[n]) {
int sid = base_index[n] + kv.second;
best = min(best, dist[sid]);
}
}
// Also consider direct edge 1->n: we initialized those states with 0 already; if there is no incoming color to n (no edges into n),
// then impossible. (Handled above)
if (best == INF) cout << -1 << '\n';
else cout << best << '\n';
return 0;
}