#include <bits/stdc++.h>
using namespace std;
const int inf = 1000000009;
const int maxn = 20009;
struct {
  int u, v;
  int cap, flow;
} e[6 * maxn];
vector<int> neigh[2 * maxn];
void addEdge(int u, int v, int cap) {
  static int ee = 0;
  e[ee].u = u;
  e[ee].v = v;
  e[ee].cap = cap;
  neigh[u].push_back(ee);
  e[ee + 1].u = v;
  e[ee + 1].v = u;
  e[ee + 1].cap = 0;
  neigh[v].push_back(ee + 1);
  ee += 2;
}
int dinic_ptr[2 * maxn];
int dinic_dist[2 * maxn];
int cnt;
int source, target;
bool dinic_bfs() {
  queue<int> Q;
  for (int i = 0; i < cnt; i++) dinic_ptr[i] = 0, dinic_dist[i] = -1;
  dinic_dist[source] = 0;
  Q.push(source);
  while (!Q.empty()) {
    int cur = Q.front();
    Q.pop();
    for (int i : neigh[cur]) {
      if (e[i].cap > e[i].flow && dinic_dist[e[i].v] == -1) {
        dinic_dist[e[i].v] = dinic_dist[cur] + 1;
        Q.push(e[i].v);
      }
    }
  }
  return dinic_dist[target] != -1;
}
int dinic_dfs(int v, int flow) {
  if (!flow) return 0;
  if (v == target) return flow;
  for (; dinic_ptr[v] < neigh[v].size(); dinic_ptr[v]++) {
    int i = neigh[v][dinic_ptr[v]];
    if (dinic_dist[e[i].v] != dinic_dist[v] + 1) continue;
    int f = dinic_dfs(e[i].v, min(flow, e[i].cap - e[i].flow));
    if (f) {
      e[i].flow += f;
      e[i ^ 1].flow -= f;
      return f;
    }
  }
  return 0;
}
int dinic() {
  int flow = 0;
  while (dinic_bfs()) {
    int inc;
    while (inc = dinic_dfs(source, inf)) flow += inc;
  }
  return flow;
}
vector<pair<int, int>> neigh1[maxn];
int posInSt[maxn];
bool vis[maxn];
int low[maxn];
vector<int> St;
void dfs(int v, int col) {
  vis[v] = true;
  posInSt[v] = St.size();
  St.push_back(col);
  low[v] = posInSt[v];
  for (auto e : neigh1[v]) {
    int u = e.first;
    if (posInSt[u] != -1 && posInSt[u] == posInSt[v] - 1) continue;
    if (posInSt[u] != -1) {
      low[v] = min(low[v], posInSt[u]);
      int sz = 0;
      addEdge(cnt, e.second, 1);
      for (int t = posInSt[u] + 1; t < St.size(); t++) {
        addEdge(cnt, St[t], 1);
        sz++;
      }
      addEdge(0, cnt, sz);
      cnt++;
    } else if (!vis[u]) {
      dfs(u, e.second);
      low[v] = min(low[v], low[u]);
    }
  }
  if (low[v] == posInSt[v] && col != -1) {
    addEdge(0, col, 1);
  }
  St.pop_back();
  posInSt[v] = -1;
}
int main() {
  int n, m;
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= m; i++) {
    int u, v, c;
    scanf("%d %d %d", &u, &v, &c);
    neigh1[u].emplace_back(v, c);
    neigh1[v].emplace_back(u, c);
  }
  for (int i = 1; i <= m; i++) {
    addEdge(i, m + 1, 1);
  }
  cnt = m + 2;
  for (int v = 1; v <= n; v++) posInSt[v] = -1;
  dfs(1, -1);
  source = 0, target = m + 1;
  printf("%d", dinic());
}
