#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
using namespace std;
//----------------------------------------------
#define CL(a,num) memset(a,num,sizeof(a));
#define BtoA(x,y) memcpy(x,y,sizeof(x));
#define eps 1e-12
#define inf 0x7fffffff
typedef __int64 LL;
//----------------------------------------------
const int Nmax = 1000 + 5;
struct Edge {int from, to, dis;};
struct HeapNode {
int d, idx;
bool operator < (const HeapNode& rhs) const {
return d > rhs.d;
}
};
struct Dijk {
int n, m;
vector<Edge> edges;
vector<int> G[Nmax];
bool vis[Nmax];
int d[Nmax];
int p[Nmax];
void init(int n) {
this->n = n;
for(int i = 1; i <= n; ++i) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int dis) {
edges.push_back((Edge){from, to, dis});
m = edges.size();
G[from].push_back(m-1); //
}
void dijk(int s) {
priority_queue<HeapNode> q;
for(int i = 1; i <= n; ++i) d[i] = inf;
d[s] = 0;
CL(vis, 0);
q.push((HeapNode){0, s});
while(!q.empty()) {
HeapNode x = q.top(); q.pop();
int idx = x.idx;
if(vis[idx]) continue;
vis[idx] = true;
for(int i = 0; i < G[idx].size(); ++i) {
Edge& e = edges[G[idx][i]];
if(d[e.to] > d[idx] + e.dis) {
d[e.to] = d[idx] + e.dis;
p[e.to] = G[idx][i];
q.push((HeapNode){d[e.to], e.to});
}
}
}
}
void Get_SP(int s, int* dis, vector<int>* path) {
//Get_Shortest_Path
dijk(s);
for(int i = 1; i <= n; ++i) {
dis[i] = d[i];
path[i].clear();
int t = i;
path[i].push_back(t);
while(t != s) {
path[i].push_back(edges[p[t]].from);
t = edges[p[t]].from;
}
reverse(path[i].begin(), path[i].end());
}
}
};
int N, M, ans;
Dijk solver;
int d[Nmax];
vector<int> path[Nmax];
int main() {
freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);
cin >> N >> M;
solver.init(N);
for(int i = 1; i <= M; ++i) {
int s, t, d;
cin >> s >> t >> d;
solver.AddEdge(s, t, d);
}
solver.Get_SP(1, d, path);
ans = d[N];
cout << ans << endl;
return 0;
}