

#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#define MAXN 110
using namespace std;
struct Node
{
int v;
int weight;
Node(int _v,int _weight):v(_v),weight(_weight){}
};
int N,M;
vector<Node> Adj[MAXN];
stack<int> TopOrder;
int vl[MAXN],ve[MAXN];
int Indegree[MAXN];
int TopSort(){
int LeastTime=0;
queue<int> q;
fill(ve,ve+N,0);
for(int i=0;i<N;i++){
if(Indegree[i]==0){
q.push(i);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
TopOrder.push(u);//保存了序列,就不需要再用cnt了
for(int i=0;i<Adj[u].size();i++){
int v=Adj[u][i].v;
if(--Indegree[v]==0){
q.push(v);
}
if(ve[u]+Adj[u][i].weight>ve[v]){
ve[v]=ve[u]+Adj[u][i].weight;
}
if(ve[v]>LeastTime) LeastTime=ve[v];
}
}
if(TopOrder.size()!=N) return 0;
else return LeastTime;
}
void CriticalPath(){
int LeastTime=TopSort();
printf("%d\n",LeastTime);
if(LeastTime==0) return;
fill(vl,vl+N,LeastTime);
while(!TopOrder.empty()){
int u=TopOrder.top();
TopOrder.pop();
for(int i=0;i<Adj[u].size();i++){
int v=Adj[u][i].v;
if(vl[v]-Adj[u][i].weight<vl[u]){
vl[u]=vl[v]-Adj[u][i].weight;
}
}
}
for(int u=0;u<N;u++){
for(int i=Adj[u].size()-1;i>=0;i--){//边起点升序,边终点按输入逆序
int v=Adj[u][i].v;
int w=Adj[u][i].weight;
int e=ve[u];
int l=vl[v]-w;
if(e==l){
printf("%d->%d\n",u+1,v+1);
}
}
}
}
int main(){
scanf("%d %d",&N,&M);
int tmp1,tmp2,tmpl;
for(int i=0;i<M;i++){
scanf("%d %d %d",&tmp1,&tmp2,&tmpl);
Adj[tmp1-1].push_back(Node(tmp2-1,tmpl));
Indegree[tmp2-1]++;//入度在输入时初始化
}
CriticalPath();
return 0;
}