#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int mod = 1000000009;
vector<pair<int, pair<int, int>>> res;
int cnt = 0;
struct custom_hash {
  static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
  }
  size_t operator()(uint64_t x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x + FIXED_RANDOM);
  }
};
void dfs(vector<pair<int, int>> adj[], bool visited[], int src, int mn,
         int tank) {
  visited[src] = true;
  int i;
  for (i = 0; i < adj[src].size(); i++) {
    if (visited[adj[src][i].first] == false) {
      dfs(adj, visited, adj[src][i].first, min(mn, adj[src][i].second), tank);
    }
  }
  if (adj[src].size() == 0) {
    if (tank != src) {
      cnt++;
      res.push_back({tank, {src, mn}});
    }
  }
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int n, p;
  cin >> n >> p;
  vector<pair<int, int>> adj[n + 1];
  int i;
  int u, v, x;
  bool visited[n + 1];
  int indegree[n + 1];
  for (i = 0; i <= n; i++) {
    visited[i] = false;
    indegree[i] = 0;
  }
  for (i = 0; i < p; i++) {
    cin >> u >> v >> x;
    adj[u].push_back({v, x});
    indegree[v]++;
  }
  for (i = 1; i <= n; i++) {
    if (visited[i] == false && indegree[i] == 0) {
      dfs(adj, visited, i, INT_MAX, i);
    }
  }
  cout << cnt << "\n";
  for (i = 0; i < res.size(); i++) {
    cout << res[i].first << " " << res[i].second.first << " "
         << res[i].second.second << "\n";
  }
}
