#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-9;
int source, sink;
int n, m, In[100005], last[100005], id[100005];
struct edge {
  int nod, jump, cap, ini;
};
vector<edge> e;
void add_edge(int a, int b, int c) {
  if (In[a] == -1)
    In[a] = e.size();
  else
    e[last[a]].jump = e.size();
  last[a] = e.size();
  e.push_back(edge{b, -1, c, c});
  if (In[b] == -1)
    In[b] = e.size();
  else
    e[last[b]].jump = e.size();
  last[b] = e.size();
  e.push_back(edge{a, -1, 0, 0});
}
int lv[100005];
bool bfs(int limit) {
  fill(lv, lv + sink + 2, 0);
  lv[source] = 1;
  queue<int> q;
  q.push(source);
  int nod, newn;
  while (!q.empty()) {
    nod = q.front();
    q.pop();
    for (int i = In[nod]; i != -1; i = e[i].jump) {
      newn = e[i].nod;
      if (lv[newn] != 0 || e[i].cap < limit) continue;
      lv[newn] = lv[nod] + 1;
      q.push(newn);
      if (newn == sink) return true;
    }
  }
  return false;
}
bool dfs(int nod, int limt) {
  if (nod == sink) return true;
  int newn;
  for (; id[nod] != -1; id[nod] = e[id[nod]].jump) {
    newn = e[id[nod]].nod;
    if (lv[nod] + 1 == lv[newn] && e[id[nod]].cap >= limt && dfs(newn, limt)) {
      e[id[nod]].cap -= limt;
      e[id[nod] ^ 1].cap += limt;
      return true;
    }
  }
  return false;
}
long long dinic() {
  for (auto &i : e) i.cap = i.ini;
  int limit = 1 << 29;
  long long flow = 0;
  while (limit) {
    if (!bfs(limit)) {
      limit >>= 1;
      continue;
    }
    for (int i = 0; i <= sink; i++) id[i] = In[i];
    while (limit > 0 && dfs(source, limit)) flow += limit;
  }
  return flow;
}
vector<pair<int, int> > g[100005];
int td[100005], low[100005], k;
stack<int> P;
bool mark[100005];
int cc, cant[100005];
vector<vector<int> > comps;
void SCC(int nod, int pad) {
  P.push(nod);
  td[nod] = low[nod] = ++k;
  for (pair<int, int> x : g[nod]) {
    int newn = x.first;
    if (newn == pad) continue;
    if (!td[newn]) {
      SCC(newn, nod);
      low[nod] = min(low[nod], low[newn]);
      if (low[newn] >= td[nod]) {
        comps.push_back({nod});
        while (comps.back().back() != newn)
          comps.back().push_back(P.top()), P.pop();
        cant[comps.size() - 1] = comps.back().size();
      }
    } else
      low[nod] = min(low[nod], td[newn]);
  }
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  srand(time(0));
  cin >> n >> m;
  for (int i = 1; i <= m; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    g[a].push_back(pair<int, int>(b, c));
    g[b].push_back(pair<int, int>(a, c));
  }
  SCC(1, 0);
  cc = comps.size();
  source = 0;
  sink = cc + m + 1;
  fill(In, In + 1 + sink, -1);
  for (int i = 0; i < cc; i++) add_edge(source, i + 1, cant[i] - 1);
  for (int i = 1; i <= m; i++) add_edge(cc + i, sink, 1);
  set<pair<int, int> > marks;
  memset(mark, 0, sizeof mark);
  int nc = 0;
  for (auto cic : comps) {
    nc++;
    for (int i : cic) mark[i] = true;
    for (int nod : cic)
      for (pair<int, int> j : g[nod])
        if (mark[j.first]) {
          add_edge(nc, cc + j.second, 1);
          marks.insert(pair<int, int>(nod, j.first));
          marks.insert(pair<int, int>(j.first, nod));
        }
    for (int i : cic) mark[i] = false;
  }
  for (int i = 1; i <= n; i++)
    for (pair<int, int> j : g[i])
      if (!marks.count(pair<int, int>(i, j.first))) {
        add_edge(source, j.second, 1);
      }
  long long sol = dinic();
  cout << sol << endl;
  return 0;
}
