#include <bits/stdc++.h>
using namespace std;
bool isprime(int64_t n) {
  for (int64_t i = 2; i * i <= n; ++i) {
    if (n % i == 0) {
      return false;
    }
  }
  return true;
}
int64_t factorial(int64_t n) {
  return (n == 1 || n == 0) ? 1 : n * factorial(n - 1);
}
int64_t gcd(int64_t a, int64_t b) {
  if (a == 0) return b;
  return gcd(b % a, a);
}
int64_t lcm(int64_t a, int64_t b) { return (a / gcd(a, b) * b); }
int64_t max(int64_t a, int64_t b) {
  int64_t sol = a > b ? a : b;
  return sol;
}
int64_t min(int64_t a, int64_t b) {
  int64_t sol = a < b ? a : b;
  return sol;
}
int64_t power(int64_t x, int64_t y) {
  int64_t ans = 1;
  while (y > 0) {
    if (y & 1) {
      ans *= x;
    }
    y >>= 1LL;
    x *= x;
  }
  return ans;
}
int64_t mod = 1000000007;
vector<int64_t> v[1001];
int64_t dia[1001];
bool visited[1001] = {false};
int64_t ans[1001][3];
int64_t a[1001];
int64_t f = 0;
void dfs(vector<int64_t> v[], int64_t s, bool visited[], int64_t x,
         int64_t mn) {
  if (v[s].size() == 0) {
    visited[s] = true;
    ans[f][0] = x;
    ans[f][1] = s;
    ans[f][2] = mn;
    f++;
    return;
  }
  visited[s] = true;
  mn = min(dia[s], mn);
  for (auto i : v[s]) {
    if (visited[i] == false) {
      dfs(v, i, visited, x, mn);
    }
  }
}
inline int64_t solve() {
  int64_t n, p, x, y, d;
  cin >> n >> p;
  set<int64_t> s, s1;
  for (int64_t i = 1; i <= p; ++i) {
    cin >> x >> y >> d;
    if (s.find(y) != s.end()) {
      s.erase(s.find(y));
    }
    if (s1.find(x) == s1.end()) {
      s.insert(x);
    }
    s1.insert(y);
    dia[x] = d;
    v[x].push_back(y);
  }
  for (auto i : s) {
    if (visited[i] == false) {
      dfs(v, i, visited, i, dia[i]);
    }
  }
  if (f == 0) {
    cout << 0;
    return 0;
  }
  cout << f << "\n";
  for (int64_t i = 0; i <= f - 1; ++i) {
    cout << ans[i][0] << " " << ans[i][1] << " " << ans[i][2] << "\n";
  }
  return 0;
}
signed main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  ;
  solve();
}
