#include <bits/stdc++.h>
using namespace std;
const int MAXN = 20010;
bool sol[MAXN];
vector<vector<int> > cycles;
vector<pair<int, int> > st;
vector<pair<int, int> > g[MAXN];
int n, m, a, b, c;
int f[MAXN], count1[MAXN], count2[MAXN];
bool akt[MAXN];
void dfs(int v) {
  sol[v] = true;
  akt[v] = true;
  for (auto it = g[v].begin(); it != g[v].end(); it++) {
    if (f[v] != it->first && sol[it->first] && akt[it->first]) {
      vector<int> cycle;
      cycle.push_back(it->second);
      auto it2 = st.rbegin();
      while (true) {
        bool end = false;
        if (it2->first == it->first) {
          end = true;
        }
        cycle.push_back(it2->second);
        it2++;
        if (end) break;
      }
      cycles.push_back(cycle);
    } else if (!sol[it->first]) {
      f[it->first] = v;
      st.push_back(make_pair(v, it->second));
      dfs(it->first);
      st.pop_back();
    }
  }
  akt[v] = false;
}
class MaxFlow {
 public:
  vector<pair<int, int> > g[50010];
  vector<pair<int, int> > edges;
  bool sol[50010];
  int n_count;
  MaxFlow(int n_count) : n_count(n_count) { edges.push_back(make_pair(0, 0)); }
  void add_edge(int a, int b, int c) {
    g[a].push_back(make_pair(b, edges.size()));
    g[b].push_back(make_pair(a, -edges.size()));
    edges.push_back(make_pair(0, c));
  }
  bool valid(int edge) {
    if (edge < 0) {
      return edges[-edge].first > 0;
    }
    return edges[edge].first < edges[edge].second;
  }
  bool finished = true;
  vector<int> estack;
  bool go(int start, int end) {
    for (int i = 0; i < n_count; i++) {
      sol[i] = false;
    }
    finished = false;
    estack.clear();
    dfs(start, end);
    if (!finished) return false;
    for (auto it = estack.begin(); it != estack.end(); it++) {
      if (*it < 0) {
        edges[-(*it)].first--;
      } else {
        edges[*it].first++;
      }
    }
    return true;
  }
  void dfs(int v, int dest) {
    sol[v] = true;
    if (v == dest) {
      finished = true;
      return;
    }
    for (auto it = g[v].begin(); it != g[v].end(); it++) {
      if (!sol[it->first] && valid(it->second)) {
        estack.push_back(it->second);
        dfs(it->first, dest);
        if (finished) return;
        estack.pop_back();
      }
    }
  }
  int max_flow(int start, int end) {
    int result = 0;
    while (go(start, end)) {
      result++;
    }
    return result;
  }
};
int main() {
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    cin >> a >> b >> c;
    g[a].push_back(make_pair(b, c));
    g[b].push_back(make_pair(a, c));
    count1[c]++;
  }
  dfs(1);
  MaxFlow mf(m + cycles.size() + 3);
  for (int i = 1; i <= m; i++) {
    mf.add_edge(0, i, 1);
  }
  for (int i = 0; i < int(cycles.size()); i++) {
    for (auto it = cycles[i].begin(); it != cycles[i].end(); it++) {
      mf.add_edge(*it, m + i + 1, 1);
    }
  }
  for (auto it = cycles.begin(); it != cycles.end(); it++) {
    for (auto it2 = it->begin(); it2 != it->end(); it2++) {
      count2[*it2]++;
    }
  }
  for (int i = 1; i <= m; i++) {
    if (count1[i] != count2[i]) {
      mf.add_edge(i, m + cycles.size() + 1, 1);
    }
  }
  for (int i = m + 1; i <= m + cycles.size(); i++) {
    mf.add_edge(i, m + cycles.size() + 2, cycles[i - m - 1].size() - 1);
  }
  mf.add_edge(m + cycles.size() + 1, m + cycles.size() + 2, 100000);
  cout << mf.max_flow(0, m + cycles.size() + 2) << endl;
}
