#include <bits/stdc++.h>
using namespace std;
void openFile() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
}
const int maxN = 1e5 + 5;
const int maxM = 1e6 + 5;
const long long INF = 1e9 + 7;
int N;
vector<int> vertex[maxN];
map<vector<int>, int> M;
int cnt = 0;
int root[maxN], reRoot[maxN];
set<int> res;
void enter() {
  cin >> N;
  for (int i = 2, _b = N; i <= _b; ++i) {
    int u, v;
    cin >> u >> v;
    vertex[u].push_back(v);
    vertex[v].push_back(u);
  }
}
void getHash(int u, int p) {
  vector<int> hash;
  hash.clear();
  for (auto v : vertex[u])
    if (v != p) {
      getHash(v, u);
      hash.push_back(root[v]);
    }
  while (hash.size() < 4) hash.push_back(INF);
  sort(hash.begin(), hash.end());
  if (M.count(hash))
    root[u] = M[hash];
  else
    root[u] = M[hash] = ++cnt;
}
void dfs(int u, int p) {
  for (auto v : vertex[u])
    if (v != p) {
      vector<int> hash;
      hash.clear();
      if (p != 0) hash.push_back(reRoot[p]);
      for (auto k : vertex[u])
        if (k != p && k != v) {
          hash.push_back(root[k]);
        }
      while (hash.size() < 4) hash.push_back(INF);
      sort(hash.begin(), hash.end());
      if (M.count(hash))
        reRoot[u] = M[hash];
      else
        reRoot[u] = M[hash] = ++cnt;
      dfs(v, u);
    }
  vector<int> hash;
  hash.clear();
  if (p != 0) hash.push_back(reRoot[p]);
  for (auto v : vertex[u])
    if (v != p) {
      hash.push_back(root[v]);
    }
  while (hash.size() < 4) hash.push_back(INF);
  sort(hash.begin(), hash.end());
  int cur;
  if (M.count(hash))
    cur = M[hash];
  else
    cur = M[hash] = ++cnt;
  if (hash.back() == INF) res.insert(cur);
}
void solve() {
  getHash(1, 0);
  dfs(1, 0);
  cout << res.size() << endl;
}
int main() {
  openFile();
  enter();
  solve();
  return 0;
}
