#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<climits>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
const int MAXN = 2e6 + 5;
struct Main {
struct Vtx {
int To;
long long Wgt;
Vtx *Next;
Vtx() : Next(NULL) {}
Vtx(int To, long long Wgt) :
To(To), Wgt(Wgt), Next(NULL) {}
};
struct VtxHead : Vtx {
Vtx *Head;
long long Dist;
void Grow(int To, long long Wgt)
{
if (Head) Next =
Next->Next = new Vtx(To, Wgt);
else Head =
Next = new Vtx(To, Wgt);
}
VtxHead() : Head(NULL),
Dist(LLONG_MAX) {}
} G[MAXN], AntiG[MAXN];
struct Unit {
int u;
long long Dist;
bool operator < (const Unit &x) const
{
return Dist > x.Dist;
}
};
inline void Search(VtxHead *Graph, int Source)
{
priority_queue<Unit> Travel;
Travel.push( (Unit) { Source, 0 } );
Graph[Source].Dist = 0;
while (!Travel.empty()) {
int From = Travel.top().u;
long long CrtDist = Travel.top().Dist;
Travel.pop();
if (CrtDist <= Graph[From].Dist)
for (register Vtx *i = Graph[From].Head;
i; i = i->Next)
if (Graph[From].Dist + i->Wgt <
Graph[i->To].Dist) {
Graph[i->To].Dist =
Graph[From].Dist + i->Wgt;
Travel.push(
(Unit) { i->To, Graph[i->To].Dist } );
}
}
}
Main(void)
{
int n, m;
scanf("%d %d", &n, &m);
while (m--) {
int u, v;
long long Wgt;
scanf("%d %d %lld",
&u, &v, &Wgt);
G[u].Grow(v, Wgt);
AntiG[v].Grow(u, Wgt);
}
Search(G, 1);
Search(AntiG, n);
printf("%lld\n", G[n].Dist);
long long MinDist = G[n].Dist;
for (register int i = 1; i <= n; ++i)
for (register Vtx *j = G[i].Head;
j; j = j->Next)
if (G[i].Dist + AntiG[j->To].Dist <
MinDist)
MinDist =
G[i].Dist + AntiG[j->To].Dist;
printf("%lld\n", MinDist);
}
};
int main()
{
delete new Main;
return 0;
}