#include <bits/stdc++.h>
typedef struct l_i {
  int32_t* data;
  unsigned size;
  unsigned capacity;
} l_i;
static const l_i l_zero_i = {0};
void l_resize_i(l_i* list) {
  if (list->capacity < 4)
    list->capacity = 4;
  else
    list->capacity <<= 2;
  list->data = (int32_t*)realloc(list->data, sizeof(int32_t) * list->capacity);
  assert(list->data != NULL);
}
void l_free_i(l_i* list) {
  free(list->data);
  *list = l_zero_i;
}
bool l_empty_i(l_i* list) { return (list->size == 0); }
void l_add_i(l_i* list, int32_t value) {
  if (list->size == list->capacity) l_resize_i(list);
  list->data[list->size] = value;
  ++list->size;
}
void l_insertAt_i(l_i* list, unsigned idx, int32_t val) {
  assert(idx <= list->size);
  if (list->size == list->capacity) l_resize_i(list);
  for (unsigned i = list->size; i > idx; --i) {
    list->data[i] = list->data[i - 1];
  }
  list->data[idx] = val;
  ++list->size;
}
void l_removeAt_i(l_i* list, unsigned idx) {
  assert(idx < list->size);
  for (unsigned i = idx; i < list->size - 1; ++i) {
    list->data[i] = list->data[i + 1];
  }
  --list->size;
}
inline void l_swap_i(l_i* list, unsigned i, unsigned j) {
  assert(i < list->size);
  assert(j < list->size);
  int32_t tmp = list->data[i];
  list->data[i] = list->data[j];
  list->data[j] = tmp;
}
l_i g[100005];
bool visited[100005];
bool dfs(int node, int parent) {
  if (visited[node]) return true;
  visited[node] = true;
  bool res = false;
  for (int _k = (0), _n = (g[node].size - 1), i = _k; i <= _n; ++i) {
    int v = g[node].data[i];
    if (v == parent) continue;
    res |= dfs(v, node);
  }
  return res;
}
int main() {
  int n, m;
  scanf("%d %d", &n, &m);
  for (int _k = (1), _n = (m), i = _k; i <= _n; ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    l_add_i(&g[u], v);
    l_add_i(&g[v], u);
  }
  int count = 0;
  for (int _k = (1), _n = (n), i = _k; i <= _n; ++i) {
    if (!visited[i] && !dfs(i, -1)) ++count;
  }
  printf("%d", count);
  return 0;
}
