#include <iostream>
#include <string.h>
using namespace std;
const int MAX_COST = 10000000;
const int MAX_NUM = 100;
int cost[MAX_NUM][MAX_NUM];
int D[MAX_NUM]; /* 保存源点到其余各个顶点的最短路径值 */
bool S[MAX_NUM]; /* 判断是否已经存入点到集合中*/
void Dijkstra(int v0, int N) /* v0: 源点cost: 邻接矩阵N: 顶点个数 */
{
for(int i = 0; i < N; ++i) {
D[i] = cost[v0][i];
S[i] = false; /* 初始化数组S中没有顶点*/
}
D[v0] = 0;
S[v0] = true;
for (int i = 0; i < N; i++) {
int minCost = MAX_COST;
int u = v0;
/* 找出当前未使用的点j的D[j]的最小值 */
for (int j = 0; j < N; ++j) {
if (!S[j] && D[j] < minCost) {
u = j;
minCost = D[j];
}
}
S[u] = true; /* 将最小值对应的u加入到顶点集S中*/
for (int j = 0; j < N; ++j) {
if (!S[j] && cost[u][j] < MAX_COST && D[u] + cost[u][j] < D[j]) {
/* 通过新加入的u点路径找到离源点v0更短的路径*/
D[j] = D[u] + cost[u][j];
}
}
}
}
int main()
{
memset(S, 0, sizeof(S));
memset(D, 0, sizeof(D));
memset(cost, 0, sizeof(cost));
int N; /* 顶点数*/
int E; /*边数*/
cin >> N;
cin >> E;
for (int i = 0; i < E; ++i) {
int v1, v2;
cin >> v1;
cin >> v2;
cin >> cost[v1][v2];
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (cost[i][j] == 0)
cost[i][j] = MAX_COST;
}
}
Dijkstra(0, N);
for (int i = 0; i < N; ++i)
cout << D[i] << endl;
return 0;
}