#include <bits/stdc++.h>
inline int read() {
  int x = 0, f = 0;
  char ch = getchar();
  while (!isdigit(ch)) f |= ch == '-', ch = getchar();
  while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
  return !f ? x : -x;
}
namespace Network {
const int inf = 1073741823;
static const int N = 50010, M = 1000010;
int dis[N], pre[N], vis[N], flo[N], que[N * 10];
int tot = 1, fir[N], nex[M], got[M], tak[M], cst[M];
inline void clear() {
  tot = 1;
  memset(fir, 0, sizeof(fir));
}
inline void AddEdge(int u, int v, int t, int w = 0) {
  nex[++tot] = fir[u], fir[u] = tot, got[tot] = v, tak[tot] = t, cst[tot] = w;
  nex[++tot] = fir[v], fir[v] = tot, got[tot] = u, tak[tot] = 0, cst[tot] = -w;
}
inline int bfs(int s, int t) {
  for (int i = 1; i <= t; ++i) dis[i] = 0;
  int l = 1, r = 1;
  dis[que[1] = s] = 1;
  while (l <= r) {
    int u = que[l++];
    for (int i = fir[u]; i; i = nex[i]) {
      if (dis[got[i]] || !tak[i]) continue;
      dis[got[i]] = dis[u] + 1, que[++r] = got[i];
    }
  }
  return dis[t];
}
inline int dfs(int u, int t, int flow) {
  int rest = flow;
  if (u == t) return flow;
  for (int i = fir[u]; i && rest; i = nex[i]) {
    if (dis[u] + 1 != dis[got[i]] || !tak[i]) continue;
    int tmp = dfs(got[i], t, std::min(tak[i], rest));
    if (!tmp) dis[got[i]] = 0;
    tak[i] -= tmp, tak[i ^ 1] += tmp, rest -= tmp;
  }
  return flow - rest;
}
inline int Maxflow(int s, int t) {
  int flow = 0;
  while (bfs(s, t)) flow += dfs(s, t, inf);
  return flow;
}
}  // namespace Network
const int N = 50010;
int tot = 1, cnt, s, t, fir[N];
int nex[N << 1], got[N << 1], col[N << 1];
inline void AddEdge(int x, int y, int c) {
  nex[++tot] = fir[x], fir[x] = tot, got[tot] = y, col[tot] = c;
}
int dfn[N], low[N], pre[N], par[N], idx;
inline void Tarjan(int u, int fa) {
  low[u] = dfn[u] = ++idx, par[u] = fa;
  for (int i = fir[u]; i; i = nex[i]) {
    if (got[i] == fa) continue;
    if (!dfn[got[i]])
      pre[got[i]] = i, Tarjan(got[i], u),
      low[u] = std::min(low[u], low[got[i]]);
    else
      low[u] = std::min(low[u], dfn[got[i]]);
  }
  for (int i = fir[u]; i; i = nex[i]) {
    if (low[got[i]] > dfn[u]) {
      ++cnt;
      Network::AddEdge(s, cnt, 1);
      Network::AddEdge(cnt, col[i], 1);
    }
    if (dfn[got[i]] > dfn[u] && par[got[i]] != u) {
      ++cnt;
      int len = 0;
      for (int idx = got[i]; idx != u; idx = par[idx])
        Network::AddEdge(cnt, col[pre[idx]], 1), ++len;
      Network::AddEdge(cnt, col[i], 1);
      Network::AddEdge(s, cnt, len);
    }
  }
}
int main() {
  int n = read(), m = read(), Max = 0;
  for (int i = 1; i <= m; ++i) {
    int u = read(), v = read(), c = read();
    AddEdge(u, v, c), AddEdge(v, u, c), Max = std::max(Max, c);
  }
  cnt = Max, s = 2 * m + 1, t = s + 1, Tarjan(1, 0);
  for (int i = 1; i <= Max; ++i) Network::AddEdge(i, t, 1);
  std::cout << Network::Maxflow(s, t) << std::endl;
  return 0;
}
